【问题标题】:How can I intercept a Compojure request and execute it based on a test?如何拦截 Compojure 请求并根据测试执行它?
【发布时间】:2014-03-06 00:01:13
【问题描述】:

我有一些路线。

(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,然后仅在响应为非零时执行检查,但这意味着我在检查身份验证之前已经执行了一个处理程序。

我关注了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")))))

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

  • 一种在处理请求之前检查响应(和一些其他逻辑)的方法
  • 我可以将其应用于大量路由的处理程序
  • 不适用于应用中的所有路由
  • 我将有多个这样的处理程序对会话进行不同类型的检查

我该怎么做呢?

【问题讨论】:

    标签: clojure compojure ring


    【解决方案1】:

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

    在你的情况下,如果你把你的other-routes放在第一位,你的问题应该解决了。

    如:

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

    记住组合路由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]
    

    【讨论】:

    • 谢谢。不过,我确实有不止一种检查,所以我认为您将非检查项目放在首位的建议不适用?我会考虑你的第二个建议。
    • 老实说,我是 Ring 的新手(对 Clojure 也很陌生)。我是否将不得不放弃我的defroutes 并重新编写我的路由才能做到这一点?还有一些功能,例如if-routedef-'ed。这是否意味着复制粘贴代码块或我错过了重点?
    • 好吧,你总是可以在你的路由处理程序中而不是在外面调用处理程序,将更新答案以显示。
    • 谢谢,最后一点解决了我现在的问题,并且在我了解其余的 compojure 和 ring 的同时足以让某些东西正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多