(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
(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
咱們能夠用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-params
、handler
前,先被傳給了print-query-params
。瀏覽器
(在瀏覽器內,咱們實際上會看到兩次輸出,是由於瀏覽器在請求url的時候,還請求了favoicon,chrome每次刷新都是兩個請求,而safari只有第一次請求了favoicon,以後刷新都沒有再次請求)app
首先,咱們將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...