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

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

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

&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;body&gt;
        &lt;script&gt;
            fetch(&#39;http://localhost:3000/messages&#39;, {
                method: &#39;POST&#39;,
                headers: { &#39;content-type&#39;: &#39;application/json&#39; },
                body: JSON.stringify({ data: &#39;foo&#39; })
            })
            .then(async response =&gt; {
                console.log(await response.json());
            });
        &lt;/script&gt;
    &lt;/body&gt;
&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

import (
	&quot;net/http&quot;
	&quot;net/http/httputil&quot;
	&quot;net/url&quot;
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc(&quot;/messages&quot;, handleRequest)

	http.ListenAndServe(&quot;:3000&quot;, mux)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
	w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
	w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)

	targetUrl, _ := url.Parse(&quot;http://localhost:3001/messages&quot;)

	proxy := httputil.NewSingleHostReverseProxy(targetUrl)
	proxy.ServeHTTP(w, r)
}

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

import (
	&quot;encoding/json&quot;
	&quot;net/http&quot;
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc(&quot;/messages&quot;, handleRequest)

	http.ListenAndServe(&quot;:3001&quot;, mux)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
	w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
	w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)

	w.WriteHeader(http.StatusOK)

	json.NewEncoder(w).Encode(&quot;bar&quot;)
}

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

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

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)
}

注意以下更改:

  1. 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(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
	w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
	w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;*&quot;)

	if r.Method == &quot;OPTIONS&quot; {
		w.WriteHeader(http.StatusOK)
		return
	}
	targetUrl, _ := url.Parse(&quot;http://localhost:3001&quot;)

	proxy := httputil.NewSingleHostReverseProxy(targetUrl)
	proxy.ServeHTTP(w, r)
}

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:

// w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)
// w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
// 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:

确定