记录响应正文时的Golang DumpResponse gzip问题(reverseproxy)

时间:2017-09-18 10:19:57

标签: go gzip reverse-proxy

我在main.go中创建了一个简单的反向代理,如下所示:

reverseproxy := httputil.NewSingleHostReverseProxy("https://someurl/someuri")

这工作正常,但是,我想记录从服务器返回的响应。我也可以使用golang推荐的标准RoundTrip方法中的以下代码来实现这一点:

response, err := http.DefaultTransport.RoundTrip(request)
dumpresp, err := httputil.DumpResponse(response, true)

if err != nil {
    return nil, err
}
log.Printf("%s", dumpresp)

以上所有工作都是预期的,除了一件事,响应,当Content-Encoding:gzip时,字符串在日志中显示为非utf8 gzip字符。它似乎是一个golang监督,但也许我在文档中遗漏了一些东西,我已经阅读了几次完成。我不能在这里发布日志,因为这些字符不是utf8所以它们无论如何都不会在这个网站上显示。所以,我知道你的想法,只需抓住gzip内容并使用一种方法来删除gzip压缩。如果来自DumpResponse的响应不是部分gzip和部分标准utf8而无法将这些部分彼此分开,那将是很好的。

所以我知道你要说什么,为什么不采取像下面的原始响应和gzip解码,并且“不”使用DumpResponse。我也可以这样做,但是存在以下问题:

var reader io.Reader
startreader := httputility.NewChunkedReader(reader)
switch response.Header.Get("Content-Encoding") {
case "gzip":
    startreader, err = gzip.NewReader(response.Body)
    log.Println("Response body gzip: ")
    buf := new(bytes.Buffer)
    buf.ReadFrom(startreader)
    b := buf.Bytes()
    s := *(*string)(unsafe.Pointer(&b))
    for name, value := range response.Header {
        var hvaluecomp string = ""
        for i := 0; i < len(value); i++ {
            hvaluecomp += value[i]
        }
        response.Header.Add(name,hvaluecomp)
    }
    log.Printf("%s", s)



default:
    startreader = response.Body
    buf := new(bytes.Buffer)
    buf.ReadFrom(startreader)
    b := buf.Bytes()
    s := *(*string)(unsafe.Pointer(&b))
    for name, value := range response.Header {
        fmt.Printf("%v: %v\n", name, value)
    }
    log.Printf("%s", s)
}

上面的问题是,响应只能通过读取器读取一次,之后反向代理不能再读取响应,它会使代理响应返回浏览器nil =),所以我再次遇到了失败。我无法想象编码golang的人会错过解码gzip,只是很奇怪,它似乎很简单。

所以最后,我的问题是,DumpResponse是否能够解压缩gzip,以便我可以记录实际响应而不是非utf8字符?在调试生产产品的问题时,这对日志阅读器没有好处。这会使内置的golang反向代理在我眼中无用,我会自己开始开发。

2 个答案:

答案 0 :(得分:0)

  

DumpResponse让我能够解压缩gzip

不,不。

对我而言,似乎主要问题既不是反向代理也不是DumpResponse,而是你正在尝试&#34; log&#34;二进制数据:无论是gzip还是其他二进制数据,如图像。只需修复您的日志记录逻辑:如果原始主体是二进制文件,您应该呈现某种表示形式或转换它。对于gziped的东西首先是gunzip(但这可能仍然是二进制&#34;非utf8&#34;数据不适合记录)。关注真正的问题:如何&#34; log&#34;二进制数据。

答案 1 :(得分:0)

答案是复制流,然后您可以使用第二个变量将流重新发布回request.body对象,这样您就不会丢失任何数据。

buf, _ := ioutil.ReadAll(response.Body)
responseuse1 := ioutil.NopCloser(bytes.NewBuffer(buf))
responsehold := ioutil.NopCloser(bytes.NewBuffer(buf))

提取日志记录的方法:extractLogging(responseuse1) 将把握推回到身体,使其不受影响:response.Body = responsehold

返回回复