gpt4 book ai didi

go - 在 Go 反向代理中在 handleFunc 和 modifyResponse 之间共享上下文

转载 作者:IT王子 更新时间:2023-10-29 02:35:31 24 4
gpt4 key购买 nike

我正在尝试学习 Go,并认为一个不错的小项目将是一个放置在网络服务器前面的 A/B 测试代理。我几乎不知道 Go 本质上提供了开箱即用的反向代理,因此设置很简单。我已经到了代理流量的地步,但问题是,我在实现实际功能时遇到了麻烦,因为无论我在哪里访问响应,我都无法访问分配的 A/B 测试变体:

  • handleFunc 中,我将每个测试的变体分配给请求,因此上游服务器也可以知道它并将 if 用于其后端的实现。
  • 我正在设置一个包含所有测试和变体的 cookie,包括代理到上游的请求和返回给客户端的响应。
  • 包含查找/替换对的测试将在响应从上游服务器返回后对响应主体进行突变。
  • 我正在尝试使用 httputil.ReverseProxymodifyResponse 函数来进行响应突变。

问题是我不知道如何在不更改上游服务器的情况下在 handleFuncmodifyResponse 之间共享指定的变体。我希望能够以某种方式共享此上下文(基本上是 map[string]string

代码示例:

这是我的代码的精简版,我的问题基本上是,modifyRequest 如何知道 handleFunc 中发生的随机分配?

package main

import (
config2 "ab-proxy/config"
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"strings"
)

var config config2.ProxyConfig
var reverseProxy *httputil.ReverseProxy
var tests config2.Tests

func overwriteCookie(req *http.Request, cookie *http.Cookie) {
// omitted for brevity, will replace a cookie header, instead of adding a second value
}

func parseRequestCookiesToAssignedTests(req *http.Request) map[string]string {
// omitted for brevity, builds a map where the key is the identifier of the test, the value the assigned variant
}

func renderCookieForAssignedTests(assignedTests map[string]string) string {
// omitted for brevity, builds a cookie string
}

func main () {
var err error

if config, err = config2.LoadConfig(); err != nil {
fmt.Println(err)

return
}

if tests, err = config2.LoadTests(); err != nil {
fmt.Println(err)

return
}

upstreamUrl, _ := url.Parse("0.0.0.0:80")

reverseProxy = httputil.NewSingleHostReverseProxy(upstreamUrl)
reverseProxy.ModifyResponse = modifyResponse

http.HandleFunc("/", handleRequest)

if err := http.ListenAndServe("0.0.0.0:80", nil); err != nil {
fmt.Println("Could not start proxy")
}
}

func handleRequest(res http.ResponseWriter, req *http.Request) {
assigned := parseRequestCookiesToAssignedTests(req)

newCookies := make(map[string]string)

for _, test := range tests.Entries {
val, ok := assigned[test.Identifier]

if ok {
newCookies[test.Identifier] = val
} else {
newCookies[test.Identifier] = "not-assigned-yet" // this will be replaced by random variation assignment
}
}

testCookie := http.Cookie{Name: config.Cookie.Name, Value: renderCookieForAssignedTests(newCookies)}

// Add cookie to request to be sent to upstream
overwriteCookie(req, &testCookie)

// Add cookie to response to be returned to client
http.SetCookie(res, &testCookie)

reverseProxy.ServeHTTP(res, req)
}

func modifyResponse (response *http.Response) error {
body, err := ioutil.ReadAll(response.Body)

if err != nil {
return err
}

err = response.Body.Close()

if err != nil {
return err
}

response.Body = ioutil.NopCloser(bytes.NewReader(body))
response.ContentLength = int64(len(body))
response.Header.Set("Content-Length", strconv.Itoa(len(body)))

return nil
}

最佳答案

使用标准 context.Context .这可以在您的处理程序中通过 *http.Request 访问。并且请求也可以通过 *http.Response 参数访问 modifyResponse

在你的处理程序中:

ctx := req.Context()
// Set values, deadlines, etc.
req = req.WithContext(ctx)
reverseProxy.ServeHTTP(res, req)

然后在 modifyResponse 中:

ctx := response.Request.Context()
// fetch values, check for cancellation, etc

关于go - 在 Go 反向代理中在 handleFunc 和 modifyResponse 之间共享上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55210593/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com