当前位置: 首页 > 工具软件 > Compojure > 使用案例 >

ring和compojure

易炳
2023-12-01

使用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)))))


 



 类似资料: