ring和compojure

来源:互联网 发布:淘宝回收手机被骗 编辑:程序博客网 时间:2024/06/07 09:55

使用clojure构建web应用程序,一般会用到这两个函数库。其中,ring负责请求和响应数据结构的转换,compojure用于路由。

当然上层还会有enlive,hiccup等web模版化的函数库。

Ring

请求和响应数据结构的转换在ring.util.servlet命名空间中实现

(defn servlet  "Create a servlet from a Ring handler.."  [handler]  (proxy [HttpServlet] []    (service [request response]      ((make-service-method handler)         this request response))))

该函数返回一个实现了HttpServlet接口的实例,并在service中对请求和响应数据进行了转换,其中handler是一个函数,接收一个包含请求信息的map,返回一个响应的map

make-service-method函数中通过调用build-request-map将HttpServletRequest实例转换成一个最基本的map

(defn build-request-map  "Create the request map from the HttpServletRequest object."  [^HttpServletRequest request]  {:server-port        (.getServerPort request)   :server-name        (.getServerName request)   :remote-addr        (.getRemoteAddr request)   :uri                (.getRequestURI request)   :query-string       (.getQueryString request)   :scheme             (keyword (.getScheme request))   :request-method     (keyword (.toLowerCase (.getMethod request)))   :headers            (get-headers request)   :content-type       (.getContentType request)   :content-length     (get-content-length request)   :character-encoding (.getCharacterEncoding request)   :ssl-client-cert    (get-client-cert request)   :body               (.getInputStream request)})

在handler处理完后,update-servlet-response函数又将一个响应的map信息设置到HttpServletResponse实例中,ring中还定义了一些基本的包装handler的函数,对request map和response map添加其他的key, value。如wrap-cookie, wrap-file等。

Compojure

通过compojure可以定义一个路由,指定不同消息的处理方法,示例如下

(defroutes app  (GET "/" [] "<h1>Hello World</h1>")  (route/not-found "<h1>Page not found</h1>"))

当收到对根的get请求时,返回Hello World, 否则返回Page not found


defroutes函数其实定义了一个函数,而在宏中的每一个form,如GET,route/not-found都是一个handler。defroutes宏最终将转换成这样一个函数

(defn xxx   [request]   (some #(% request) handlers))

根据some的行为,执行完第一个返回值非nil的handler后将返回,所以定义路由时需要注意各路由的先后顺序。

其实,GET也是一个宏,类似的宏还有POST,HEAD,DELETE等,这些宏生成的handler会先根据请求方法,以及路径匹配进行判断,如果不匹配则返回nil,这样就可以较给下一个handler处理, 这类宏大概转换后的函数可参考make-route

(defn make-route  "Returns a function that will only call the handler if the method and Clout  route match the request."  [method route handler]  (if-method method    (if-route route      (fn [request]        (render (handler request) request)))))


 



原创粉丝点击