【问题标题】:Clojure Cross Origin Error - Totally LostClojure 跨域错误 - 完全丢失
【发布时间】:2020-01-21 15:47:21
【问题描述】:

我在 Clojure 中有以下使用 Compojure 的简单服务器(这是一种环形模式)。一切都在开发中运行良好,现在我处于生产状态,我无法让 CORS 为我的一生工作 - 我有一个 wrap-preflight 函数,它似乎工作正常,但我在终端中不断收到 CORS 错误并且我的评论系统的帖子或获取请求都不起作用。我完全迷失了,非常沮丧,我四处打听,似乎没有人知道。

这是主要的core.clj 代码 - 如果有人有任何想法告诉我。您可以在 thedailyblech.com 上实时查看错误(不是广告,但可能有助于调试)。

谢谢!

(ns clojure-play.core
  (:use     org.httpkit.server
            [compojure.core :refer :all]
            [compojure.route :as route]
            [clojure.data.json :as json]
            [clojure.tools.logging :only [info]]
            [clojure-play.routes :as routes]
            [ring.middleware.json :only [wrap-json-body]]
            [ring.middleware.cors :refer [wrap-cors]])
  (:require [monger.core :as mg]
            [monger.collection :as mc]
            [clojure.edn :as edn]
            [clojure.java.io :as io]
            [compojure.handler :as handler])
  (:import [org.bson.types ObjectId]
           [com.mongodb DB WriteConcern])
  (:gen-class))
(println "in the beginning was the command line...")

(defonce channels (atom #{}))

(defn connect! [channel]
  (info "channel open")
  (swap! channels conj channel))

(defn notify-clients [msg]
  (doseq [channel @channels]
    (send! channel msg)))

(defn disconnect! [channel status]
  (info "channel closed:" status)
  (swap! channels #(remove #{channel} %)))


(defn ws-handler [request]
  (with-channel request channel
    (connect! channel)
    (on-close channel (partial disconnect! channel))
    (on-receive channel #(notify-clients %))))

(defn my-routes [db]
  (routes
   (GET "/foo" [] "Hello Foo")
   (GET "/bar" [] "Hello Bar")
   (GET "/json_example/:name" [] routes/json_example)
   (GET "/json_example" [] routes/json_example)
   (POST "/email" [] routes/post_email)
   (POST "/write_comment" [] (fn [req] (routes/write_comment req db)))
   (POST "/update_comment" [] (fn [req] (routes/update_comment req db)))
   (GET "/read_comments/:path" [path] (fn [req] (routes/read_comments req db path)))
   (GET "/read_comments/:path1/:path2" [path1 path2] (fn [req] (routes/read_comments req db (str path1 "/" path2))))
   (GET "/ws" [] ws-handler)))

(defn connectDB []
  (defonce connection
    (let
     [uri "mongodb://somemlabthingy"
      {:keys [conn db]} (mg/connect-via-uri uri)]
      {:conn conn
       :db db}))
  {:db (:db connection)
   :conn (:conn connection)})

(def cors-headers
  "Generic CORS headers"
  {"Access-Control-Allow-Origin"  "*"
   "Access-Control-Allow-Headers" "*"
   "Access-Control-Allow-Methods" "GET POST OPTIONS DELETE PUT"})

(defn preflight?
  "Returns true if the request is a preflight request"
  [request]
  (= (request :request-method) :options))

(defn -main
  "this is main"
  [& args]

  (println "hello there main")

  (def db (get (connectDB) :db))

  (println (read-string (slurp (io/resource "environment/config.edn"))))


  (defn wrap-preflight [handler]
    (fn [request]
      (do
        (println "inside wrap-preflight")
        (println "value of request")
        (println request)
        (println "value of handler")
        (println handler)
        (if (preflight? request)
          {:status 200
           :headers cors-headers
           :body "preflight complete"}
          (handler request)))))

  (run-server
   (wrap-preflight
    (wrap-cors
     (wrap-json-body
      (my-routes db)
      {:keywords? true :bigdecimals? true})
     :access-control-allow-origin [#"http://www.thedailyblech.com"]
     :access-control-allow-methods [:get :put :post :delete :options]
     :access-control-allow-headers ["Origin" "X-Requested-With"
                                    "Content-Type" "Accept"]))
   {:port 4000}))

【问题讨论】:

  • 应该将"Access-Control-Allow-Methods" "GET POST OPTIONS DELETE PUT" 改为"Access-Control-Allow-Methods" "GET, POST, OPTIONS, DELETE, PUT" 吗?

标签: http clojure request cors preflight


【解决方案1】:

CORS 中间件自动处理预检内容——您不需要单独的中间件,也不需要生成自己的标头等。

你让它包裹了routes,这是正确的——所以首先进行CORS检查,然后是路由。您应该删除您的自定义预检中间件,它应该可以在那时工作。

我们在工作中使用wrap-cors,我们遇到的唯一问题是允许足够的标头(一些由生产基础设施插入,例如负载平衡器)。我们最终得到了这个:

                           :access-control-allow-headers #{"accept"
                                                           "accept-encoding"
                                                           "accept-language"
                                                           "authorization"
                                                           "content-type"
                                                           "origin"}

对于它的价值,以下是我们所拥有的方法:

                           :access-control-allow-methods [:delete :get
                                                          :patch :post :put]

(你不需要:options

【讨论】:

  • 谢谢伙计。原来是 NGINX 问题。网络是一堆牙签,我告诉你。欣赏!
  • 啊,可能类似于我们最初使用 CloudFront 时遇到的问题,以及它会/不会传递哪些标头。
  • @SeanCorfield,我在使用 system.components 时遇到了类似的问题,并且标题似乎不在响应中。你能帮忙吗? stackoverflow.com/questions/60536686/…
【解决方案2】:

研究了几个小时后,我发现thisring-cors github 上的issues post 非常有帮助,但文档严重缺乏。

使用链接的要点,我能够解决 CORS 问题:

; Copied from linked gist
(def cors-headers
  "Generic CORS headers"
  {"Access-Control-Allow-Origin"  "*"
   "Access-Control-Allow-Headers" "*"
   "Access-Control-Allow-Methods" "GET"})

(defn preflight?
  "Returns true if the request is a preflight request"
  [request]
  (= (request :request-method) :options))

(defn all-cors
  "Allow requests from all origins - also check preflight"
  [handler]
  (fn [request]
    (if (preflight? request)
      {:status 200
       :headers cors-headers
       :body "preflight complete"}
      (let [response (handler request)]
        (update-in response [:headers]
                   merge cors-headers )))))

; my -main
(defn -main
  "Main entry point"
  [& args]
  (let [port (Integer/parseInt (or (System/getenv "PORT") "8081"))]

  (server/run-server
    (all-cors
      (wrap-defaults #'app-routes site-defaults))
        {:port port})
    (println "Running on" port)))

这终于让我能够看到在 Chrome 开发工具中正确设置的标头,并且还摆脱了我的 React 前端的警告。

Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *

【讨论】:

    【解决方案3】:

    可能值得尝试并添加一个明确的

    (OPTIONS "/*" req handle-preflight)
    

    路由到您的 Compojure 路由 - 就我而言,这就是它起作用的原因。

    【讨论】:

      【解决方案4】:

      (RING-MIDDLEWARE-CORS/wrap-cors

      :access-control-allow-credentials "true"

      :access-control-allow-origin [#".*"]

      :access-control-allow-headers #{"接受" “接受编码” “接受语言” “授权” “内容类型” “起源”}

      :access-control-allow-methods [:get :put :post :delete :options])

      【讨论】:

      • 我是一名 clojure 和 clojurescript 开发人员。帮我解决这个问题。此设置正在使用中。 @Minal Chauhan 你为什么要-1?如果没有实际使用的例子,那是相当混乱的,所以我把它放上来。
      猜你喜欢
      • 2016-11-04
      • 2010-11-23
      • 2010-10-25
      • 2010-09-30
      • 2011-12-19
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      • 2023-04-05
      相关资源
      最近更新 更多