它有助于可视化中间件实际上是什么。
(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 示例,希望它更有意义。