Это помогает визуализировать, что такое промежуточное ПО на самом деле.
(defn middleware [handler]
(fn [request]
;; ...
;; Do something to the request before sending it down the chain.
;; ...
(let [response (handler request)]
;; ...
;; Do something to the response that's coming back up the chain.
;; ...
response)))
Вот тут-то и наступил момент ага для меня.
На первый взгляд сбивает с толку то, что промежуточное ПО не применяется к запросу, о чем вы думаете.
Напомним, что приложение Ring — это просто функция, которая принимает запрос и возвращает ответ (что означает, что это обработчик):
((fn [request] {:status 200, ...}) request) ;=> response
Давайте немного уменьшим масштаб. Получаем еще один обработчик:
((GET "/" [] "Hello") request) ;=> response
Давайте еще немного уменьшим масштаб. Находим обработчик my-routes
:
(my-routes request) ;=> response
Ну а что, если вы хотите что-то сделать перед отправкой запроса обработчику my-routes
? Вы можете обернуть его другим обработчиком.
((fn [req] (println "Request came in!") (my-routes req)) request) ;=> response
Это немного трудно читать, поэтому давайте разберемся для ясности. Мы можем определить функцию, которая возвращает этот обработчик. Промежуточное ПО — это функции, которые берут обработчик и обертывают его другим обработчиком. Он не возвращает ответ. Он возвращает обработчик, который может вернуть ответ.
(defn println-middleware [wrapped-func]
(fn [req]
(println "Request came in!")
(wrapped-func req)))
((println-middleware my-route) request) ;=> response
И если нам нужно что-то сделать до того, как даже println-middleware
получит запрос, то мы можем завернуть его еще раз:
((outer-middleware (println-middleware my-routes)) request) ;=> response
Суть в том, что my-routes
, как и ваша my-handler
, является единственной именованной функцией, которая фактически принимает запрос в качестве аргумента.
Последняя демонстрация:
(handler3 (handler2 (handler1 request))) ;=> response
((middleware1 (middleware2 (middleware3 handler1))) request) ;=> response
Я так много пишу, потому что могу сочувствовать. Но вернитесь к моему первому примеру middleware
, надеюсь, он имеет больше смысла.
person
danneu
schedule
18.10.2013