这是我的用例
我们有一个服务"foobar"有两个版本legacy
和version_2_of_doom
(都在去)
为了使从过渡legacy
到version_2_of_doom
,我们想在第一时间,有两个版本的旁边,并有POST请求(因为在这个只有一个POST API调用)对两个接收.
我看待怎么做的方式.将会
修改legacy
处理程序开头的代码,以便将请求复制到version_2_of_doom
func(w http.ResponseWriter, req *http.Request) { req.URL.Host = "v2ofdoom.local:8081" req.Host = "v2ofdoom.local:8081" client := &http.Client{} client.Do(req) // legacy code
但它似乎并不像这样直截了当
它失败了 http: Request.RequestURI can't be set in client requests.
是否有一种众所周知的方法来执行此类操作(即,不接触地转移)http.Request
到另一台服务器?
您需要将所需的值复制到新请求中.由于这与反向代理的功能非常相似,因此您可能需要查看"net/http/httputil"的用途ReverseProxy
.
创建新请求,并仅复制要发送到下一个服务器的请求部分.如果您打算在两个地方使用它,您还需要读取并缓冲请求正文:
func handler(w http.ResponseWriter, req *http.Request) { // we need to buffer the body if we want to read it here and send it // in the request. body, err := ioutil.ReadAll(req.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // you can reassign the body if you need to parse it as multipart req.Body = ioutil.NopCloser(bytes.NewReader(body)) // create a new url from the raw RequestURI sent by the client url := fmt.Sprintf("%s://%s%s", proxyScheme, proxyHost, req.RequestURI) proxyReq, err := http.NewRequest(req.Method, url, bytes.NewReader(body)) // We may want to filter some headers, otherwise we could just use a shallow copy // proxyReq.Header = req.Header proxyReq.Header = make(http.Header) for h, val := range req.Header { proxyReq.Header[h] = val } resp, err := httpClient.Do(proxyReq) if err != nil { http.Error(w, err.Error(), http.StatusBadGateway) return } defer resp.Body.Close() // legacy code }
根据我的经验,实现此目的的最简单方法是简单地创建新请求并将所需的所有请求属性复制到新请求对象中:
func(rw http.ResponseWriter, req *http.Request) { url := req.URL url.Host = "v2ofdoom.local:8081" proxyReq, err := http.NewRequest(req.Method, url.String(), req.Body) if err != nil { // handle error } proxyReq.Header.Set("Host", req.Host) proxyReq.Header.Set("X-Forwarded-For", req.RemoteAddr) for header, values := range req.Header { for _, value := range values { proxyReq.Header.Add(header, value) } } client := &http.Client{} proxyRes, err := client.Do(proxyReq) // and so on...
这种方法的好处是不修改原始请求对象(可能你的处理函数或生活在堆栈中的任何中间件函数仍然需要原始对象?).