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

查看:17
本文介绍了使用 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.

我遇到的唯一限制"是,由于 app-routes 有未找到的路由,它需要放在最后,否则会在找到 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 层以及需要使用任何*"等定义 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天全站免登陆