Understanding Clojure Ring Middleware

咱们先建立一个handler

(ns middleware-example
  (:use ring.adapter.jetty
        ring.middleware.params))

(defn handler [request]
    {:headers {}
     :status 200
     :body (str "Hello word!" )})

(def app
  handler)

;; Start the server if it hasn't already been started
(defonce server (ring.adapter.jetty/run-jetty #'app {:port 7071 :join? false}))

咱们看到,handler会接收一个request参数,并返回一个hash-map,hash-map包括headers、status和body,这个hash-map就是一个response。
党咱们访问 http://localhost:7071/ ,就会看到 Hello word!html

用middleware处理response

(defn shout
  [handler]
  (fn [request]
    (let [response (handler request)]
      (update-in response [:body] clojure.string/upper-case)))) ;; 将response中的body转换成大写

(def app
  (-> handler
    shout))

当咱们刷新页面的时候,结果就变成了 HELLO WORD!
这个例子说明,咱们能够经过middleware改变response。web

用middleware处理request

咱们能够用middle更好的解析、处理request,请看下面的例子chrome

(ns middleware-example
  (:use ring.adapter.jetty
        ring.middleware.params))

(defn print-query-params [handler]
  (fn [request]
    (println "In print-query-params, the params is:" (:query-params request))
    (handler request)))

(defn handler [request]
  (println "In handler, the params is:" (:query-params request))
  (let [name ((:query-params request) "name")]
    {:headers {}
     :status 200
     :body (str "Hello " name "!")}))

(def app
  (-> handler
      wrap-params
      print-query-params))

;; Start the server if it hasn't already been started
(defonce server (ring.adapter.jetty/run-jetty #'app {:port 7071 :join? false}))

访问 http://localhost:7071?name=mike 后,在console里咱们将看到express

In print-query-params, the params is: nil
In handler, the params is: {name mike}

这段代码能够说明,params是被wrap-params所解析出来的,request在创给wrap-paramshandler前,先被传给了print-query-params浏览器

(在浏览器内,咱们实际上会看到两次输出,是由于浏览器在请求url的时候,还请求了favoicon,chrome每次刷新都是两个请求,而safari只有第一次请求了favoicon,以后刷新都没有再次请求)app

Middleware

首先,咱们将handler这个参数传给middleware,这个middleware会返回一个方法,
这个方法会接收一个request参数,咱们能够在这个方法里生成新的request,并把这个request传给handler(handler new-request),获得返回后,咱们又能够对response进行操做。框架

经过app的定义(-> handler wrap-params print-query-params),咱们知道,middleware就像洋葱皮同样,一层层包裹handler。koa

最后面的包裹在最外层,request一层层经过middleware,每一层均可以对request进行操做,最后handler 会根据最终的request生成response,而后response又一层层传出middleware,每一层middleware有有机会对生成的response作处理。ide

就像下图同样(注意,后面的middleware,处于最外层)。
图片描述ui

其余框架的中间件

rack也是使用同样的模型处理中间件。rack使用use方法注册middleware,并将注册的middleware放入@use这个实例变量里。
rack有一个to_app的方法,在这个方法内@use.reverse.inject(app) { |a,e| e[a] },把最早注册的middleware放在最外层,并包裹好。

ring、rack、koa的middleware都是使用洋葱模型,但express的middleware却不同,middleware只是一层一层传下去的,好比要记录请求时间,就须要写两个中间件。

var app = express()

app.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

小结

Middleware能够用来对response和request进行处理(好比解析params),也能够中断执行(好比过滤ip)等。
但须要注意middleware的顺序,最后的middleware被放在了最外层。最外层,最早处理request,最后处理response。

参考

https://codenoble.com/blog/un...
https://expressjs.com/en/guid...
http://liujiacai.net/blog/201...

相关文章
相关标签/搜索