为了账号安全,请及时绑定邮箱和手机立即绑定

转到 http,使用 client.Do 将传入的 http.request 发送到其他服务器

转到 http,使用 client.Do 将传入的 http.request 发送到其他服务器

Go
慕桂英546537 2021-12-07 10:03:50
这是我的用例我们有一个服务“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.是否有一种众所周知的方法来执行这种操作(即在不接触的情况下传输)ahttp.Request到其他服务器?
查看完整描述

3 回答

?
慕妹3146593

TA贡献1820条经验 获得超9个赞

您需要将所需的值复制到新请求中。由于这与反向代理的作用非常相似,您可能需要查看“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

}


查看完整回答
反对 回复 2021-12-07
?
狐的传说

TA贡献1804条经验 获得超3个赞

根据我的经验,实现这一点的最简单方法是简单地创建一个新请求并将您需要的所有请求属性复制到新的请求对象中:


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...

这种方法的好处是不修改原始请求对象(也许您的处理程序函数或存在于堆栈中的任何中间件函数仍然需要原始对象?)。


查看完整回答
反对 回复 2021-12-07
?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

使用原始请求(仅在原始请求仍需要时才复制或复制):


func handler(w http.ResponseWriter, r *http.Request) {

    // Step 1: rewrite URL

    URL, _ := url.Parse("https://full_generic_url:123/x/y")

    r.URL.Scheme = URL.Scheme

    r.URL.Host = URL.Host

    r.URL.Path = singleJoiningSlash(URL.Path, r.URL.Path)

    r.RequestURI = ""


    // Step 2: adjust Header

    r.Header.Set("X-Forwarded-For", r.RemoteAddr)


    // note: client should be created outside the current handler()

    client := &http.Client{} 

    // Step 3: execute request

    resp, err := client.Do(r)

    if err != nil {

        http.Error(w, err.Error(), http.StatusInternalServerError)

        return

    }


    // Step 4: copy payload to response writer

    copyHeader(w.Header(), resp.Header)

    w.WriteHeader(resp.StatusCode)

    io.Copy(w, resp.Body)

    resp.Body.Close()

}


// copyHeader and singleJoiningSlash are copy from "/net/http/httputil/reverseproxy.go"

func copyHeader(dst, src http.Header) {

    for k, vv := range src {

        for _, v := range vv {

            dst.Add(k, v)

        }

    }

}


func singleJoiningSlash(a, b string) string {

    aslash := strings.HasSuffix(a, "/")

    bslash := strings.HasPrefix(b, "/")

    switch {

    case aslash && bslash:

        return a + b[1:]

    case !aslash && !bslash:

        return a + "/" + b

    }

    return a + b

}


查看完整回答
反对 回复 2021-12-07
  • 3 回答
  • 0 关注
  • 196 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信