nginx - 使用 Clojure 和 Ring 的 HTTPS 请求

标签 nginx https clojure routes ring

我正在使用 RingCompojure 开发 Clojure 网络 API。 API 需要能够接受基于指定路由的 HTTP 和 HTTPS 请求。

例如:

考虑以下应用程序路由:

(defroutes app-routes               
           (POST "/route-one" {request :request} (processRequet request))
           (POST "/route-two" {request :request} (processRequet request)))

我希望route-one 只接受 HTTP 请求,route-two 只接受 HTTPS 请求。

这可能吗?

我尝试使用以下设置运行 jetty:

(jetty/run-jetty #'app {:join? false :ssl? true :ssl-port 8443 :keystore "./resources/keystore.jks" :key-password "12345678"})

这使 API 能够接受 HTTPS 请求,但不会阻止对相同路由的 HTTP 请求。

我也试过禁用 HTTP 协议(protocol),但没有成功:

(jetty/run-jetty #'app {:port 5000 :join? false :ssl? true :ssl-port 8443 :keystore "./resources/keystore.jks" :key-password "12345678" :http? false})

根据我在网上看到的,Ring HTTPS 请求的标准流程是使用nginx 作为反向代理来管理所有 HTTPS 请求。

但是我还没有在网上找到任何实现。

有什么想法吗?

最佳答案

实现此目的的一种简单方法是检查路由中传入请求的方案,例如:

(defroutes app-routes
  (POST "/route-one" request
        (if (= (:scheme req) :http)
          (process-requet request)
          {:status 403 :body "https not supported"}))
  (POST "/route-two" request
        (if (= (:scheme req) :https)
          (process-requet request)
          {:status 403 :body "http not supported"})))

您当然可以将此方案检查提取到一个单独的函数或宏中,因此即使您有很多路由,这也是一个可行的选择,而不会在您的代码中产生过多的干扰。

如果您有很多路由,并且不想为每个路由添加额外的调用或检查,那么实现此目的的另一种方法是向您的应用程序添加一些中间件。中间件可以检查请求中包含的 :scheme 并拒绝不符合要求的请求。例如:

(defn wrap-https-only [handler]
  (fn [req]
    (if (= (:scheme req) :https)
      (handler req)
      {:status 403 :body "http not supported"})))

(defn wrap-http-only [handler]
  (fn [req]
    (if (= (:scheme req) :http)
      (handler req)
      {:status 403 :body "https not supported"})))

棘手的部分是您想要有选择地将此中间件应用于某些路由而不是其他路由,而 Compojure 没有提供执行此操作的简单方法。如果您在所有 http 路由和所有 https 路由(对它们进行分组)中都有一些公共(public)路径,那么您可以使用这样的模式:

(def http-routes
  (-> (routes (POST "/http-only/route-one" request
                    (process-requet request)))
      wrap-http-only))

(def https-routes
  (-> (routes (POST "/http-only/route-two" request
                    (process-requet request)))
      wrap-https-only))


(defroutes app-routes
  (ANY "/http-only/*" [] http-routes)
  (ANY "/https-only/*" [] https-routes))

您可以在此处看到中间件应用于路由的每个子集,因此只有在路径的第一部分匹配时才会执行。现在您可以根据需要添加任意数量的路由,中间件将负责对所有路由进行方案检查。请注意,此方法要求您可以在初始“app-routes”路由中以某种方式识别路由子集,在这种情况下,我已通过路径识别它们。

检查方案时要注意一件事:请注意,如果您决定将 SSL 卸载到负载均衡器,这将不起作用。在这种情况下,您的应用程序将始终接收 HTTP(而非 HTTPS)请求。您通常可以通过简单地检查 X-Forwarded-Proto header 而不是 :scheme 值来实现相同的目的。

关于nginx - 使用 Clojure 和 Ring 的 HTTPS 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40136412/

相关文章:

nginx - 将 Google Analytics 跟踪代码段注入(inject) Nginx 反向代理背后的网站

java - Spring Boot docker无法连接到mysql(连接被拒绝/createCommunicationsException)

nginx - 使用 nginx 将 url 重写为子域,使其可以通过两者访问

javascript - Ajax 获取请求在使用 HTTPS 的 Safari 中不起作用

java - 如何为camel-https4配置trustStore

sorting - 如何在 clojure 中根据另一个向量的值对一个向量进行排序

nginx - nginx 有软退出吗?

node.js - 如何将 http 代理与 node.js https 一起使用?

Clojure 命名空间

clojure - 将模式和结果作为向量传递给 core.match/match 的宏