Clojure:heroku 上的 wrap-ssl-redirect?

Clojure: wrap-ssl-redirect on heroku?

我刚刚尝试添加此包装器 (-> routes (wrap-ssl-redirect)) 以自动将 http 重定向到 https,但是当我部署到 heroku 时,https:// 在我的浏览器和网站中没有变绿未加载。

不是默认的 heroku 端口 443,它也应该是 wrap-ssl-redirect 函数的默认端口吗?

怎么了?

谢谢!

编辑:

我的代码:

(defn prod-app [routes]
  (-> routes
      (wrap-keyword-params)
      (wrap-params)
      (wrap-ssl-redirect)))

(defn -main []
  (let [port (Integer/parseInt (get (System/getenv) "PORT" "5000"))]
    (jetty/run-jetty (prod-app domain-specific-routes)
                     {:port port :join? false})))

编辑 2:

我刚找到可以解决我的问题的帖子:

想出了这个 require-https 处理程序 fn:

(defn https-url [request-url]
  (str "https://" 
       (:server-name request-url) 
       ":" 
       (:server-port request-url) 
       (:uri request-url)))

(defn require-https
  [handler]
  (fn [request]
    (if (and (= (:scheme request) :http) 
             (= (get-in request [:headers "host"]) "secure.mydomain.com"))
      (ring.util.response/redirect (https-url request))
      (handler request))))

但是当我尝试连接到 http://secure.mydomain.com 时,我在浏览器地址栏中看到一个端口 https://secure.mydomain.com:80/ 并收到此消息 ERR_SSL_PROTOCOL_ERROR

在 Heroku 上,你需要 bind to the port 他们给你一个环境变量。 Heroku 还在您的应用程序前面安装了负载均衡器。它们将终止 SSL 连接并通过 HTTP 与您的应用程序通信,因此您的应用程序看到的方案将始终是 HTTP。标准 wrap-ssl-redirect 在这种情况下不会很好地工作,我认为它永远不会成功重定向(它会认为用户正在通过 HTTP 连接,即使他们确实被重定向到 HTTPS)。

但是 Heroku 将 x-forwarded-proto 添加到每个请求的 headers 中以解决此问题,因此您可以查看您的客户端使用的协议。在同一个 ring.middleware.ssl 命名空间中是一个 wrap-forwarded-scheme 中间件。

"Middleware that changes the :scheme of the request map to the value present in a request header. This is useful if your application sits behind a reverse proxy or load balancer that handles the SSL transport. The header defaults to x-forwarded-proto."

如果你先用这个包装你的路由,然后用 wrap-ssl-redirect,它应该正确重定向到 HTTPS。您还可以添加 ring.middleware.ssl/wrap-hsts 以强制执行 HSTS

(wrap-forwarded-scheme (wrap-ssl-redirect (wrap-hsts app)))

万岁 lib-noir 和它的 wrap-force-ssl fn。

我只是需要稍微更改一下以满足我的需要(我有一个 SSL 证书。即使我的 clojure 应用程序处理一个以上的域)

这是我的 fn:

(defn wrap-force-ssl
  "Almost like in lib-noir. 
   If the request's scheme is not https [and is for 'secure.'], redirect with https.
   Also checks the X-Forwarded-Proto header."
  [app]
  (fn [req]
    (let [headers (:headers req)
          host    (headers "host")]
      (if (or (= :https (:scheme req))
              (= "https" (headers "x-forwarded-proto"))
              (not= "secure.mydomain.com" host)) ;you might not need this!
        (app req)
        (noir.response/redirect (str "https://" host (:uri req)) :permanent)))))

感谢 Chris Granger 和朋友们!