已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查

新手上路,请多包涵

我已经创建了旅行服务器。它工作正常,我们能够发出 POST Insomnia 的请求,但是当我们在前端发出 POST 的请求时,它会发送错误:

 has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

我们对axios的要求:

 let config = {
headers: {
  "Content-Type": "application/json",
  'Access-Control-Allow-Origin': '*',
  }
}

let data = {
  "id": 4
 }

 axios.post('http://196.121.147.69:9777/twirp/route.FRoute/GetLists', data, config)
   .then((res) => {
      console.log(res)
     })
    .catch((err) => {
      console.log(err)
   });
}

我的去文件:

 func setupResponse(w *http.ResponseWriter, req *http.Request) {
    (*w).Header().Set("Access-Control-Allow-Origin", "*")
    (*w).Header().Set("Access-Control-Allow-Methods", "POST,GET,OPTIONS, PUT, DELETE")

    (*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}

func WithUserAgent(base http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

    ctx := r.Context()
    ua := r.Header.Get("Jwt")
    ctx = context.WithValue(ctx, "jwt", ua)

    r = r.WithContext(ctx)

    setupResponse(&w, r)
     base.ServeHTTP(w, r)
  })
}

const (
    host     = "localhost"
    port     = 5432
    user     = "postgres"
    password = "postgres"
    dbname   = "postgres"
)

func main() {

    psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
           "password=%s dbname=%s sslmode=disable",
               host, port, user, password, dbname)

    server := &s.Server{psqlInfo}

    twirpHandler := p.NewFinanceServiceServer(server, nil)

    wrap := WithUserAgent(twirpHandler)
      log.Fatalln(http.ListenAndServe(":9707", wrap))
}

正如我之前在 Insomnia 上所说,它工作得很好,但是当我们发出 axios POST 请求时,在浏览器的控制台上出现以下内容:

已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:它没有 HTTP 正常状态。

原文由 GGG 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 3k
2 个回答

我相信这是最简单的例子:

 header := w.Header()
header.Add("Access-Control-Allow-Origin", "*")
header.Add("Access-Control-Allow-Methods", "DELETE, POST, GET, OPTIONS")
header.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")

您还可以为 Access-Control-Max-Age 添加标头,当然您可以允许任何您想要的标头和方法。

最后你想回应最初的请求:

 if r.Method == "OPTIONS" {
    w.WriteHeader(http.StatusOK)
    return
}

编辑(2019 年 6 月):我们现在为此使用 大猩猩。他们的东西得到了更积极的维护,而且他们已经这样做了很长时间。留下旧的链接,以防万一。

下面的旧中间件推荐: 当然,为此使用中间件可能会更容易。我不认为我已经使用过它,但是 这个 似乎是强烈推荐的。

原文由 trey-jones 发布,翻译遵循 CC BY-SA 4.0 许可协议

这个答案解释了幕后发生的事情,以及如何用任何语言解决这个问题的基础知识。有关参考,请参阅 有关此主题的 MDN 文档

您正在从一个域(比如 domain-a.com)上运行的 JavaScript 向另一个域(domain-b.com)上运行的 API 发出 URL 请求。当您这样做时,浏览器必须询问 domain-b.com 是否可以允许来自 domain-a.com 的请求。它通过 HTTP OPTIONS 请求来实现。然后,在响应中,domain-b.com 上的服务器必须(至少)提供以下 HTTP 标头,上面写着“是的,没关系”:

 HTTP/1.1 204 No Content                            // or 200 OK
Access-Control-Allow-Origin: https://domain-a.com  // or * for allowing anybody
Access-Control-Allow-Methods: POST, GET, OPTIONS   // What kind of methods are allowed
...                                                // other headers

如果您使用的是 Chrome,您可以通过按 F12 并转到“网络”选项卡来查看 domain-b.com 上的服务器给出的响应,从而查看响应的样子。

因此,回到@threeve 的原始答案的最低限度:

 header := w.Header()
header.Add("Access-Control-Allow-Origin", "*")

if r.Method == "OPTIONS" {
    w.WriteHeader(http.StatusOK)
    return
}

这将允许任何人从任何地方访问这些数据。由于其他原因,他包含的其他标头是必需的,但这些标头是通过 CORS(跨源资源共享)要求的最低要求。

原文由 Ryan Shillington 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题