英文:
How to proxy a preflight request with status OK using Go?
问题
给定一个发出HTTP请求的客户端:
<!DOCTYPE html>
<html>
<body>
<script>
fetch('http://localhost:3000/messages', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ data: 'foo' })
})
.then(async response => {
console.log(await response.json());
});
</script>
</body>
</html>
API服务器无法处理该请求,请求处理程序应充当代理并将请求发送到另一个服务器:
import (
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/messages", handleRequest)
http.ListenAndServe(":3000", mux)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
targetUrl, _ := url.Parse("http://localhost:3001/messages")
proxy := httputil.NewSingleHostReverseProxy(targetUrl)
proxy.ServeHTTP(w, r)
}
目标服务器应处理该请求并发送响应:
import (
"encoding/json"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/messages", handleRequest)
http.ListenAndServe(":3001", mux)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode("bar")
}
我启动了两个服务器并运行了.html文件,我期望在控制台中看到:
bar
但不幸的是,我收到了错误信息:
Access to fetch at 'http://localhost:3000/messages' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
有人知道如何解决这个问题吗?
英文:
Given a client making a HTTP request
<!DOCTYPE html>
<html>
<body>
<script>
fetch('http://localhost:3000/messages', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ data: 'foo' })
})
.then(async response => {
console.log(await response.json());
});
</script>
</body>
</html>
The API server does not handle the request, the request handler should act as a proxy and send the request to another server
import (
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/messages", handleRequest)
http.ListenAndServe(":3000", mux)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
targetUrl, _ := url.Parse("http://localhost:3001/messages")
proxy := httputil.NewSingleHostReverseProxy(targetUrl)
proxy.ServeHTTP(w, r)
}
The target server should handle the request and send back the response
import (
"encoding/json"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/messages", handleRequest)
http.ListenAndServe(":3001", mux)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode("bar")
}
I start both servers and run the .html file, I would expect a
> bar
in the console. But unfortunately I get the error
> Access to fetch at 'http://localhost:3000/messages' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Does someone know how to fix this?
答案1
得分: 5
你需要为代理添加一个处理预检请求的不同路径。
以下是你的代理应该如何看起来的示例代码:
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
targetUrl, _ := url.Parse("http://localhost:3001")
proxy := httputil.NewSingleHostReverseProxy(targetUrl)
proxy.ServeHTTP(w, r)
}
注意以下更改:
OPTIONS
请求(预检请求)不会传递给服务器,你只需通过发送OK
状态来接受它们。
2.(与 CORS 问题无关)目标 URL 不应包含 /message
部分。路径部分已经包含在你的请求中,不需要重复。
此外,你需要更改服务器代码并删除这些头部信息:
// w.Header().Set("Access-Control-Allow-Origin", "*")
// w.Header().Set("Access-Control-Allow-Headers", "*")
// w.Header().Set("Access-Control-Allow-Methods", "*")
这些头部信息已经由代理设置。服务器不再响应 web 浏览器。
英文:
You need to add a different path for handling preflight requests in your proxy.
this is how your proxy should look like:
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
targetUrl, _ := url.Parse("http://localhost:3001")
proxy := httputil.NewSingleHostReverseProxy(targetUrl)
proxy.ServeHTTP(w, r)
}
Notice the changes:
-
OPTION
requests(preflights) are not passed to server, you just accept them by sending aOK
status. -
(irrelevant to CORS problem) target url should not have
/message
part. path part is already present in your request, you should not repeat it.
Also you need to change the server code and remove these headers:
// w.Header().Set("Access-Control-Allow-Origin", "*")
// w.Header().Set("Access-Control-Allow-Headers", "*")
// w.Header().Set("Access-Control-Allow-Methods", "*")
They are already set by the proxy. Server doesn't respond to the web-browser anymore.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论