How to proxy a preflight request with status OK using Go?

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

How to proxy a preflight request with status OK using Go?

问题

给定一个发出HTTP请求的客户端:

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <script>
  5. fetch('http://localhost:3000/messages', {
  6. method: 'POST',
  7. headers: { 'content-type': 'application/json' },
  8. body: JSON.stringify({ data: 'foo' })
  9. })
  10. .then(async response => {
  11. console.log(await response.json());
  12. });
  13. </script>
  14. </body>
  15. </html>

API服务器无法处理该请求,请求处理程序应充当代理并将请求发送到另一个服务器:

  1. import (
  2. "net/http"
  3. "net/http/httputil"
  4. "net/url"
  5. )
  6. func main() {
  7. mux := http.NewServeMux()
  8. mux.HandleFunc("/messages", handleRequest)
  9. http.ListenAndServe(":3000", mux)
  10. }
  11. func handleRequest(w http.ResponseWriter, r *http.Request) {
  12. w.Header().Set("Access-Control-Allow-Origin", "*")
  13. w.Header().Set("Access-Control-Allow-Headers", "*")
  14. w.Header().Set("Access-Control-Allow-Methods", "*")
  15. targetUrl, _ := url.Parse("http://localhost:3001/messages")
  16. proxy := httputil.NewSingleHostReverseProxy(targetUrl)
  17. proxy.ServeHTTP(w, r)
  18. }

目标服务器应处理该请求并发送响应:

  1. import (
  2. "encoding/json"
  3. "net/http"
  4. )
  5. func main() {
  6. mux := http.NewServeMux()
  7. mux.HandleFunc("/messages", handleRequest)
  8. http.ListenAndServe(":3001", mux)
  9. }
  10. func handleRequest(w http.ResponseWriter, r *http.Request) {
  11. w.Header().Set("Access-Control-Allow-Origin", "*")
  12. w.Header().Set("Access-Control-Allow-Headers", "*")
  13. w.Header().Set("Access-Control-Allow-Methods", "*")
  14. w.WriteHeader(http.StatusOK)
  15. json.NewEncoder(w).Encode("bar")
  16. }

我启动了两个服务器并运行了.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

  1. &lt;!DOCTYPE html&gt;
  2. &lt;html&gt;
  3. &lt;body&gt;
  4. &lt;script&gt;
  5. fetch(&#39;http://localhost:3000/messages&#39;, {
  6. method: &#39;POST&#39;,
  7. headers: { &#39;content-type&#39;: &#39;application/json&#39; },
  8. body: JSON.stringify({ data: &#39;foo&#39; })
  9. })
  10. .then(async response =&gt; {
  11. console.log(await response.json());
  12. });
  13. &lt;/script&gt;
  14. &lt;/body&gt;
  15. &lt;/html&gt;

The API server does not handle the request, the request handler should act as a proxy and send the request to another server

  1. import (
  2. &quot;net/http&quot;
  3. &quot;net/http/httputil&quot;
  4. &quot;net/url&quot;
  5. )
  6. func main() {
  7. mux := http.NewServeMux()
  8. mux.HandleFunc(&quot;/messages&quot;, handleRequest)
  9. http.ListenAndServe(&quot;:3000&quot;, mux)
  10. }
  11. func handleRequest(w http.ResponseWriter, r *http.Request) {
  12. w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
  13. w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
  14. w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)
  15. targetUrl, _ := url.Parse(&quot;http://localhost:3001/messages&quot;)
  16. proxy := httputil.NewSingleHostReverseProxy(targetUrl)
  17. proxy.ServeHTTP(w, r)
  18. }

The target server should handle the request and send back the response

  1. import (
  2. &quot;encoding/json&quot;
  3. &quot;net/http&quot;
  4. )
  5. func main() {
  6. mux := http.NewServeMux()
  7. mux.HandleFunc(&quot;/messages&quot;, handleRequest)
  8. http.ListenAndServe(&quot;:3001&quot;, mux)
  9. }
  10. func handleRequest(w http.ResponseWriter, r *http.Request) {
  11. w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
  12. w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
  13. w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)
  14. w.WriteHeader(http.StatusOK)
  15. json.NewEncoder(w).Encode(&quot;bar&quot;)
  16. }

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.

How to proxy a preflight request with status OK using Go?

Does someone know how to fix this?

答案1

得分: 5

你需要为代理添加一个处理预检请求的不同路径。
以下是你的代理应该如何看起来的示例代码:

  1. func handleRequest(w http.ResponseWriter, r *http.Request) {
  2. w.Header().Set("Access-Control-Allow-Origin", "*")
  3. w.Header().Set("Access-Control-Allow-Headers", "*")
  4. w.Header().Set("Access-Control-Allow-Methods", "*")
  5. if r.Method == "OPTIONS" {
  6. w.WriteHeader(http.StatusOK)
  7. return
  8. }
  9. targetUrl, _ := url.Parse("http://localhost:3001")
  10. proxy := httputil.NewSingleHostReverseProxy(targetUrl)
  11. proxy.ServeHTTP(w, r)
  12. }

注意以下更改:

  1. OPTIONS 请求(预检请求)不会传递给服务器,你只需通过发送 OK 状态来接受它们。

2.(与 CORS 问题无关)目标 URL 不应包含 /message 部分。路径部分已经包含在你的请求中,不需要重复。

此外,你需要更改服务器代码并删除这些头部信息:

  1. // w.Header().Set("Access-Control-Allow-Origin", "*")
  2. // w.Header().Set("Access-Control-Allow-Headers", "*")
  3. // 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:

  1. func handleRequest(w http.ResponseWriter, r *http.Request) {
  2. w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
  3. w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
  4. w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)
  5. if r.Method == &quot;OPTIONS&quot; {
  6. w.WriteHeader(http.StatusOK)
  7. return
  8. }
  9. targetUrl, _ := url.Parse(&quot;http://localhost:3001&quot;)
  10. proxy := httputil.NewSingleHostReverseProxy(targetUrl)
  11. proxy.ServeHTTP(w, r)
  12. }

Notice the changes:

  1. OPTION requests(preflights) are not passed to server, you just accept them by sending a OK status.

  2. (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:

  1. // w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
  2. // w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
  3. // w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)

They are already set by the proxy. Server doesn't respond to the web-browser anymore.

huangapple
  • 本文由 发表于 2022年12月30日 17:02:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/74959810.html
匿名

发表评论

匿名网友

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

确定