nginx-使用Clojure和Ring的HTTPS请求

我正在使用Ring和Compojure开发Clojure Web API.
API必须能够根据指定的路由接受HTTP和HTTPS请求.

例如:

考虑以下应用程序路由:

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

我希望路由一仅接受HTTP请求,而路由二仅接受HTTPS请求.

这可能吗?

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

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

这使API可以接受HTTPS请求,但是并没有阻止HTTP请求到相同的路由.

我也尝试过禁用HTTP协议,但是没有运气:

(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路由(将它们分组)中都有一些公用路径,则可以使用以下模式:

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

您可以在此处看到中间件已应用于路由的每个子集,因此仅在路径的第一部分匹配时才执行中间件.现在,您可以添加任意数量的路由,中间件将负责所有路由的方案检查.请注意,这种方法要求您可以以某种方式在初始“应用程序路由”路由中标识路由的子集,在这种情况下,我已经通过路径标识了它们.

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

上一篇:如何在Clojurescript中循环执行JavaScript对象并将每个对象推入数组


下一篇:java-如何正确读取Clojure中的RandomAccessFile?