如何拦截Compojure请求并根据测试执行它?

时间:2014-03-05 15:10:52

标签: clojure compojure ring

我有一些路线。

(defroutes some-routes
    (GET "one" [] one)
    (GET "two" [] two))

(defroutes other-routes
  (GET "three" [] three)
  (GET "four" [] four))

(defroutes more-routes
  (GET "five" [] five)
  (GET "six" [] six))


(def all-routes 
  (routes app-routes
          (-> some-routes session/wrap-session my-interceptor)
          (-> more-routes session/wrap-session my-other-interceptor)
          other-routes))

我想拦截some-routes但不拦截other-routes并根据请求执行测试(检查会话中是否存在密钥以及其他一些内容)。我不止一个。 my-other-interceptor做同样的事但不同。

所以我从这开始:

(defn my-interceptor [handler]
    (fn [request]
      (prn (-> request :session :thing-key))
        (let [thing (-> request :session :thing-key-id)]
          (if (nil? thing)
            (-> (response "Not authenticated"))
            (handler request)))))

如果在会话中设置了:thing-key,这将允许访问处理程序。

不幸的是,这不适合拥有多套路线。此检查仅适用于some-routes而非other-routes。但是在我们执行处理程序之前,我们不知道路由是否匹配。此时处理程序已经执行了。我可以重写它来执行handler然后只检查响应是否为非零,但这意味着我在检查auth之前执行了一个处理程序。

我跟着this example,显示了问题:

(defn add-app-version-header [handler]
  (fn [request]
    (let [resp (handler request)
      headers (:headers resp)]
      (assoc resp :headers 
        (assoc headers "X-APP-INFO" "MyTerifficApp Version 0.0.1-Alpha")))))

我该怎么做?我想要的是:

  • 在处理请求之前检查响应(以及其他一些逻辑)的方法
  • 我可以申请一系列大型路线的处理程序
  • 未应用于应用中的所有路线
  • 我会让不止一个这样的处理程序对会话进行不同类型的检查

我该怎么做呢?

1 个答案:

答案 0 :(得分:1)

使用单独的处理程序或中间件的方法是使用compojure.core/routes分解路由,并仅在需要时使用处理程序。

在您的情况下,如果您先放置other-routes,则应解决您的问题。

如:

(def app-routes
   (compojure.core/routes
       other-routes
       (-> some-routes
           session/wrap-session
           my-interceptor)))

记住compojure路由are just ring handlers,您始终可以编写一个自定义defroutes,仅当路由与请求匹配时才调用您的处理程序,这是make route source code

(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)))))

这样,如果您有多个条件处理程序,则不需要依赖于将这些路径放在合成的末尾。

请注意,如果您希望保持路线处理代码清洁,则采用这种方法。

(my-def-routes routes
    (GET "/" request (show-all request))

如果您不想自己动作defroutes,只需在内部调用拦截器:

(defroutes routes
   (GET "/" request (interceptor request show-all))

(defn interceptor
  [request handler]