无论服务器如何处理,都会遇到CORS错误的HTTP调用问题。

huangapple go评论106阅读模式
英文:

Running into CORS error with any HTTP call regardless of it being handled on the server

问题

我有一个用Go编写的简单服务器。然后我有一个作为项目前端的简单Nextjs应用程序。问题是,每当我尝试从前端获取后端时,就会出现“常规”CORS错误。

我知道前端会进行HTTP OPTIONS的预检调用,并检查标头等等,但是在查看了许多StackOverflow帖子后,似乎找到了解决方案,但没有任何效果。

这是源代码:

package main

import (
    "encoding/json"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

type ClassReturn struct {
    Errcode int         `json:"errcode"`
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
}

func main() {
    r := mux.NewRouter()
    router(r)
    log.Fatal(http.ListenAndServe(":8000", r))
}

func router(r *mux.Router) {
    r.HandleFunc("/get", corsHandler(handleOutput)).Methods("GET", "OPTIONS")
    r.HandleFunc("/post", corsHandler(handleOutput)).Methods("POST", "OPTIONS")
}

func corsHandler(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if r.Method == "OPTIONS" {
            log.Print("preflight detected: ", r.Header)
            w.Header().Add("Connection", "keep-alive")
            w.Header().Add("Access-Control-Allow-Origin", "http://localhost:3000")
            w.Header().Add("Access-Control-Allow-Methods", "POST, OPTIONS, GET, DELETE, PUT")
            w.Header().Add("Access-Control-Allow-Headers", "content-type")
            w.Header().Add("Access-Control-Max-Age", "86400")
            return
        } else {
            handleOutput(w, r)
        }
    }
}

func handleOutput(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(ClassReturn{
        Errcode: 0,
        Message: "stuff endpoint",
        Data:    r.Method,
    })
}

这是当我获取Go端点时收到的控制台消息(对于get端点,但对于post端点也是一样的):

localhost/:1 Access to XMLHttpRequest at 'http://localhost:8000/get' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

在网络选项卡中,我得到了由CORS阻止的失败的GET +预检HTTP请求。

无论是POST还是GET调用都不起作用,即使我将Access-Control-Allow-Originhttp://localhost:3000更改为*也不行。

我尝试了不同的方法,比如:

但以上这些都没有起作用。

我还在Go的Discord服务器上提问过,但他们提示我使用上述的解决方案,而这些解决方案并不起作用。

如果有人知道可能解决我的问题的方法,我会非常高兴。

英文:

I have a simple server written in Go. I then have a simple Nextjs app that acts as the frontend of my project. The issue is that whenever I try to fetch the backend from the frontend, the normal CORS error pops out.

Now, I know that the frontend does a preflight call with HTTP OPTIONS and it checks headers and so on, but after looking at dozens of StackOverflow posts with what seemed to be a solution, nothing worked.

This is the source code

package main

import (
    "encoding/json"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

type ClassReturn struct {
    Errcode int         `json:"errcode"`
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
}

func main() {
    r := mux.NewRouter()
    router(r)
    log.Fatal(http.ListenAndServe(":8000", r))
}

func router(r *mux.Router) {
    r.HandleFunc("/get", corsHandler(handleOutput)).Methods("GET", "OPTIONS")
    r.HandleFunc("/post", corsHandler(handleOutput)).Methods("POST", "OPTIONS")
}

func corsHandler(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if r.Method == "OPTIONS" {
            log.Print("preflight detected: ", r.Header)
            w.Header().Add("Connection", "keep-alive")
            w.Header().Add("Access-Control-Allow-Origin", "http://localhost:3000")
            w.Header().Add("Access-Control-Allow-Methods", "POST, OPTIONS, GET, DELETE, PUT")
            w.Header().Add("Access-Control-Allow-Headers", "content-type")
            w.Header().Add("Access-Control-Max-Age", "86400")
            return
        } else {
            handleOutput(w, r)
        }
    }
}

func handleOutput(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(ClassReturn{
        Errcode: 0,
        Message: "stuff endpoint",
        Data:    r.Method,
    })
}

This is the console message I get when fetching the go endpoint (for the get endpoint, but I do get the same for the post endpoint)


localhost/:1 Access to XMLHttpRequest at 'http://localhost:8000/get' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

In the network tab I get the failed HTTP Request with GET + Preflight blocked by CORS

Neither a POST nor a GET call works, nor does it if I change the Access-Control-Allow-Origin from http://localhost:3000 to *

I tried different things, like those

But none of those above have worked.

I have also asked on the Discord server of Go but they prompt me to use these very solutions I have above, which don't work

If anyone knows a possible solution to my issue I would be delighted

答案1

得分: 1

解决方案

func corsHandler(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        log.Print("preflight detected: ", r.Header)
        w.Header().Add("Connection", "keep-alive")
        w.Header().Add("Access-Control-Allow-Origin", "http://localhost:3000")
        w.Header().Add("Access-Control-Allow-Methods", "POST, OPTIONS, GET, DELETE, PUT")
        w.Header().Add("Access-Control-Allow-Headers", "content-type")
        w.Header().Add("Access-Control-Max-Age", "86400")

        // 继续处理我的方法
        handleOutput(w, r)
    }
}

解释

经过一些检查(并得到了@mkopriva的帮助),我发现我的前端代码没有进入代码中的if语句,所以我的HTTP请求不是OPTIONS请求,而是直接的GET请求。然而,由于CORS策略,Access-Control-Allow-Origin头部从未设置,所以我的请求失败了。

移除控制语句(if r.Method == "OPTIONS")允许后端始终设置头部,因此即使是简单的请求,我的fetch也不会失败。

附注

这里需要做一个小的附注。通常,使用HTTP GET发出Preflight请求(用于CORS)是很奇怪的。在这里明确说明并有详细文档说明:“某些请求不会触发CORS预检请求。”“XMLHttpRequest和fetch可以向任何源提交简单请求。”现在,我在我的Next.js项目中使用的是axios,所以它使用的是XMLHttpRequest。文章中提到:“服务器仍然必须使用Access-Control-Allow-Origin来共享响应”。

这篇文章中写的内容应该是在构建前端与后端的时候的一个重要参考,无论是在本地环境还是开发环境。

另一个附注

我花了几个小时的时间弄清楚为什么添加自定义头部会破坏CORS。答案就在我眼前,因为CORS策略中的"Access-Control-Allow-Headers"没有正确设置我在请求中发送的头部。考虑到我使用的是"Authorization: Bearer ***",如果我不这样做,CORS就会出错;

w.Header().Add("Access-Control-Allow-Headers", "Authorization, content-type")

这篇文章对我帮助很大。

希望这能解决你的疑问,如有需要,请随时改进这个答案。

英文:

SOLUTION

func corsHandler(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        log.Print("preflight detected: ", r.Header)
        w.Header().Add("Connection", "keep-alive")
        w.Header().Add("Access-Control-Allow-Origin", "http://localhost:3000")
        w.Header().Add("Access-Control-Allow-Methods", "POST, OPTIONS, GET, DELETE, PUT")
        w.Header().Add("Access-Control-Allow-Headers", "content-type")
        w.Header().Add("Access-Control-Max-Age", "86400")

        // continue with my method
        handleOutput(w, r)
    }
}

EXPLANATION

After some checks (and help from @mkopriva), I found out that my frontend was not entering the if in the code, so my HTTP call was not OPTIONS, but directly GET. However, due to the CORS policy, headers were never set for Access-Control-Allow-Origin, so my call was failing.

Removing the control (if r.Method == "OPTIONS") allowed the backend to always set headers so even on simple calls, my fetch would not fail

SIDE NOTE

There is a necessity to make a little side note here. Usually, it is strange to HTTP GET to make a Preflight request (for CORS). It is stated and well documented here that Some requests don't trigger a CORS preflight. XMLHttpRequest and fetch can submit simple requests to any origin. Now, I was using axios in my Next.js project, so it was using a XMLHttpRequest. the server still must opt-in using Access-Control-Allow-Origin to share the response

This was written in the article linked above and should be a key reference when building a frontend with a backend, both in a localhost/development environment.

ANOTHER SIDE NOTE

I lost several hours of my time figuring out why adding custom headers was breaking CORS. The answer was in front of my eyes, as the CORS Policy "Access-Control-Allow-Headers" did not have the correct headers I sent on request. Considering I use "Authorization: Bearer ***", if I do not do like this, CORS breaks;

w.Header().Add("Access-Control-Allow-Headers", "Authorization, content-type")

This article helped me a lot

I hope this clears any doubt, feel free to improve this answer

huangapple
  • 本文由 发表于 2022年11月12日 19:12:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/74412377.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定