使用Ring和Compojure为具有不同中间件的应用和API路由提供服务 [英] Serving app and api routes with different middleware using Ring and Compojure

查看:73
本文介绍了使用Ring和Compojure为具有不同中间件的应用和API路由提供服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ring + compojure应用程序,我想根据路由是Web应用程序的一部分还是api(基于json)的一部分来应用不同的中间件。

I have a ring+compojure application and I want to apply different middleware depending on whether the route is part of the web application or part of the api (which is json based).

我在堆栈溢出和其他论坛上找到了该问题的一些答案,但这些答案似乎比我一直使用的解决方案复杂。我想知道我的操作方式是否有缺点以及解决方案中可能缺少的内容。我正在做的事情的一个非常简化的版本是

I found some answers to this question on stack overflow and other forums, but these answers seem more complicated than the solution I've been using. I wanted to know if there are drawbacks with how I'm doing it and what I may be missing in my solution. A very simplified version of what I'm doing is

  (defroutes app-routes
    (GET "/" [req] dump-req)
    (route/not-found "Not Found"))

(defroutes api-routes
  (GET "/api" [req] dump-req))

(def app
  (routes (-> api-routes
              (wrap-defaults api-defaults))
          (-> app-routes
              (wrap-defaults site-defaults))))

请注意,还有更多中间件比我在这里展示的要好。

Note that there is more middleware than I have shown here.

我遇到的唯一限制是,由于应用程序路由具有未找到的路由,因此它需要排在最后,否则在找到之前会被触发api路线。

The only 'restriction' I've encountered is that as the app-routes has the not-found route, it needs to come last or it will be triggered before finding the api routes.

这似乎比我发现的其他一些解决方案更简单,更灵活,这些解决方案似乎都使​​用了附加的条件中间件,例如ring.middleware.conditional或其他在我看来,这是更复杂的路由定义,其中有一个额外的defroutes层,并且需要使用ANY *等定义defroutes。

This seems simpler and more flexible than some of the other solutions I've found, which appear to either use additional conditional middleware, such as ring.middleware.conditional or what seems to me as more complex routing definitions where there is an additional defroutes layer and the need to define defroutes with ANY "*" etc.

我怀疑其中有些微妙的地方在这里不见了,虽然我的方法似乎行得通,但在某些情况下,它将导致意外的行为或结果。

I suspect there is something subtle I'm missing here and while my approach seems to work, it will cause unexpected behaviour or results in some situations etc.

推荐答案

您是正确的,排序很重要,而且您缺少一个精妙之处-您对 api-routes 应用的中间件将对所有请求执行。

You are correct, the ordering matters and there is a subtlety you are missing - the middleware you apply to api-routes is executed for all requests.

考虑以下代码:

(defn wrap-app-middleware
  [handler]
  (fn [req]
    (println "App Middleware")
    (handler req)))

(defn wrap-api-middleware
  [handler]
  (fn [req]
    (println "API Middleware")
    (handler req)))

(defroutes app-routes
  (GET "/" _ "App")
  (route/not-found "Not Found"))

(defroutes api-routes
  (GET "/api" _ "API"))

(def app
  (routes (-> api-routes
              (wrap-api-middleware))
          (-> app-routes
              (wrap-app-middleware))))

和repl会话:

> (require '[ring.mock.request :as mock])
> (app (mock/request :get "/api"))
API Middleware
...
> (app (mock/request :get "/"))
API Middleware
App Middleware
...

Compojure具有不错的功能和帮助程序,可以在中间件匹配后将中间件应用于路由 -环绕路线

Compojure has a nice feature and helper that applies middleware to routes after they have been matched - wrap-routes

(def app
  (routes (-> api-routes
              (wrap-routes wrap-api-middleware))
          (-> app-routes
              (wrap-routes wrap-app-middleware))
          (route/not-found "Not Found")))

> (app (mock/request :get "/api"))
API Middleware
...
> (app (mock/request :get "/"))
App Middleware
...

这篇关于使用Ring和Compojure为具有不同中间件的应用和API路由提供服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆