CORS问题 – React/Axios前端和Golang后端

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

CORS issue - React/Axios Frontend and Golang Backend

问题

我有一个用Golang编写的后端REST API服务。我在React前端中使用axios来向API发送POST请求。尽管我认为我已经在前端和后端都启用了CORS,但浏览器仍然抛出以下错误:

由于预检响应的Access-Control-Allow-Headers不允许请求头字段access-control-allow-origin,因此已阻止从源'http://localhost:3000'访问'http://localhost:8080/winERC20'的XMLHttpRequest。

请问有人能提供解决方法吗?

main.go

func main() {
    fmt.Println("Server is serving at http://localhost:8080/")
    // 初始化mux路由器
    router := mux.NewRouter()
    router.HandleFunc("/", helloHandler)
    router.HandleFunc("/matchingABI", api.MatchingContractABI)
    router.HandleFunc("/winERC20", api.WinERC20_controller).Methods("POST", "OPTIONS")
    log.Fatal(http.ListenAndServe(":8080", router))
}

api.go

func WinERC20_controller(w http.ResponseWriter, r *http.Request) {
    enableCors(&w)

    if r.Method == "OPTIONS" {
        w.WriteHeader(http.StatusOK)
        return
    }
    // 尝试将请求体解码为结构体。如果有错误,向客户端返回错误消息和400状态码。
    var p winERC20_RequestBody
    err := json.NewDecoder(r.Body).Decode(&p)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    ...

    w.Header().Set("Content-Type", "application/json")
    resp := make(map[string]string)
    resp["message"] = "Success"
    jsonResp, err := json.Marshal(resp)
    if err != nil {
        log.Fatalf("JSON编组时发生错误。错误:%s", err)
    }
    w.Write(jsonResp)
}

func enableCors(w *http.ResponseWriter) {
    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")
}

frontend.js

grantERC20(){
    // 将ERC20转移到玩家账户
    let url = 'http://localhost:8080/winERC20'
    let config = {
        headers: {
            "Content-Type": "application/json",
            'Access-Control-Allow-Origin': '*',
        }
    }
    let data = {
        "PublicAddress" : this.props.account,
        "Amount": this.props.score
    }
    axios.post(url, data, config)
    .then(
        (response) => {console.log(response)},
        (error) => {console.log(error);}
    );
}

componentDidMount () {
    this.grantERC20()
}

以上是您提供的代码的翻译。

英文:

I have a backend REST API service written in Golang. I used axios in the React frontend to POST to the API. Even though I think I have enabled the CORS for both the frontend and backend, the browser still throws this error:

> Access to XMLHttpRequest at 'http://localhost:8080/winERC20' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.

Can anyone please suggest what I should do to solve this?

main.go

func main() {
	fmt.Println("Server is serving at http://localhost:8080/")
	// Init the mux router
	router := mux.NewRouter()
	router.HandleFunc("/", helloHandler)
	router.HandleFunc("/matchingABI", api.MatchingContractABI)
	router.HandleFunc("/winERC20", api.WinERC20_controller).Methods("POST", "OPTIONS")
	log.Fatal(http.ListenAndServe(":8080", router))
}

api.go

    func WinERC20_controller(w http.ResponseWriter, r *http.Request) {
    	enableCors(&w)

        if r.Method == "OPTIONS" {
	        w.WriteHeader(http.StatusOK)
	        return
        }
    	// Try to decode the request body into the struct. If there is an error,
    	// respond to the client with the error message and a 400 status code.
    	var p winERC20_RequestBody
    	err := json.NewDecoder(r.Body).Decode(&p)
    	if err != nil {
    		http.Error(w, err.Error(), http.StatusBadRequest)
    		return
    	}
    
    	...
    
    	w.Header().Set("Content-Type", "application/json")
    	resp := make(map[string]string)
    	resp["message"] = "Success"
    	jsonResp, err := json.Marshal(resp)
    	if err != nil {
    		log.Fatalf("Error happened in JSON marshal. Err: %s", err)
    	}
    	w.Write(jsonResp)
    }
    
    func enableCors(w *http.ResponseWriter) {
    	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")
    }

frontend.js

grantERC20(){
        // Transfer ERC20 to the player
        let url = 'http://localhost:8080/winERC20'
        let config = {
            headers: {
                "Content-Type": "application/json",
                'Access-Control-Allow-Origin': '*',
            }
        }
        let data = {
            "PublicAddress" : this.props.account,
            "Amount": this.props.score
        }
        axios.post(url, data, config)
        .then(
            (response) => {console.log(response)},
            (error) => {console.log(error);}
        );
    }

componentDidMount () {
        this.grantERC20()
}

答案1

得分: 1

为什么在你的客户端代码中,你要在请求中添加一个名为Access-Control-Allow-Origin的头部?这个头部是一个_响应_头部,而不是一个_请求_头部。此外,由于你的CORS配置不允许这样的请求头,CORS预检将会失败:

header.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")

解决方法很简单:只需从你的请求中删除Access-Control-Allow-Origin头部。

此外,你应该考虑使用一些经过验证的CORS中间件,而不是手动实现CORS(这样容易出错),比如https://github.com/rs/cors。

英文:

Why, in your client-side code, are you adding a header named Access-Control-Allow-Origin to your request? That header is a response header, not a request header. Moreover, CORS preflight is bound to fail because your CORS configuration doesn't allow such a request header:

header.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")

The remedy is simple: just drop that Access-Control-Allow-Origin header from your request.

Besides, instead of implementing CORS "manually" (which is error-prone), you should consider relying on some proven CORS middleware, such as https://github.com/rs/cors.

答案2

得分: -1

TL;DR: 在React前端中使用Fetch替代Axios,并将后端API的URL(http://localhost:8080)添加为package.json中的proxy

我遇到了相同的问题,在花了一整天的时间尝试各种可用的解决方案后,我通过将Axios调用替换为fetch来解决了这个问题。

在Frontend.js中:

await fetch("http://localhost:8080/winERC20", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams(data),
});

在Package.json中:

"proxy":"http://localhost:8080",

编辑:我已经安装了CORS扩展程序。

英文:

TL;DR: Use Fetch instead of Axios in the React Frontend and add the backend API URL (http://localhost:8080) as proxy in package.json.

I faced the same issue, and after spending a day into it, trying each and every solution available, I came to a fix by replacing the Axios call with fetch.

In Frontend.js:

 await fetch("http://localhost:8080/winERC20", {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body: new URLSearchParams(data),
    });

In Package.json:

"proxy":"http://localhost:8080",

Edit: I had installed the CORS extension

huangapple
  • 本文由 发表于 2022年3月24日 06:27:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/71594818.html
匿名

发表评论

匿名网友

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

确定