req icon indicating copy to clipboard operation
req copied to clipboard

Dump 请求和响应内容时,怎么分别获取到请求包和相应包?

Open shadow1ng opened this issue 1 year ago • 11 comments

resp.Dump() 获取到的是请求包+响应包。这个只能自己根据strings.inde去分割数据,然后获取到请求包、响应包?

shadow1ng avatar Oct 16 '22 15:10 shadow1ng

dump支持只dump指定部分内容,比如只dump request 部分。然后response部分就不在dump中,但可以从resp对象的字段中获取:

	client := req.C()
	resp, err := client.R().EnableDumpWithoutResponse().Get(url)
	if err != nil {
		...
	}
	reqContent := resp.Dump()
	respHeader := resp.Header
	respBody := resp.String()

imroc avatar Oct 17 '22 02:10 imroc

也考虑过支持更灵活的dump能力,但这种需求不多,改动较大,就暂时没支持

imroc avatar Oct 17 '22 02:10 imroc

dump支持只dump指定部分内容,比如只dump request 部分。然后response部分就不在dump中,但可以从resp对象的字段中获取:

	client := req.C()
	resp, err := client.R().EnableDumpWithoutResponse().Get(url)
	if err != nil {
		...
	}
	reqContent := resp.Dump()
	respHeader := resp.Header
	respBody := resp.String()

3q。 扫描器的话,对dump还是有需求的,需要请求包和响应包

shadow1ng avatar Oct 17 '22 03:10 shadow1ng

扫描器场景确实需要,今天已经初步支持了, release 到了 v3.25.0,用法参考 : https://req.cool/docs/tutorial/debugging/#dump-the-content

var reqBuf, respBuf bytes.Buffer
resp, err := client.R().
  EnableDump().
  SetDumpOptions(&req.DumpOptions{
    RequestOutput:  &reqBuf,
    ResponseOutput: &respBuf,
    RequestHeader:  true,
    RequestBody:    true,
    ResponseHeader: true,
    ResponseBody:   true,
  }).
  SetBody("test body").
  Post("https://httpbin.org/post")
if err != nil {
	...
}

fmt.Println("request content:")
fmt.Println(reqBuf.String())
fmt.Println("\n======\n")
fmt.Println("response content:")
fmt.Println(respBuf.String())

imroc avatar Oct 17 '22 06:10 imroc

可以的。 但有个问题,就是如果请求失败,reqBuf.String()获取不到数据

shadow1ng avatar Oct 17 '22 09:10 shadow1ng

嗯,如果是连接超时之类的网络错误,请求根本没有发出去,也就无法dump出来。

如果希望这种情况也能知道请求内容,可以用 client.OnBeforeRequest(xx) 加个中间件,每次请求前读取 request 上设置的属性(req.RawURL, req.Method, req.Headers, req.Body, req.FormData)

imroc avatar Oct 17 '22 10:10 imroc

使用respBuf.String() 的话,有什么函数能自动解码(gzip)嘛? image

shadow1ng avatar Oct 17 '22 11:10 shadow1ng

默认就会自动解压的,前提是server正常响应 Content-Encoding: gzip 的 header,并且body内容也完全是gzip算法压缩的,就会自动解压,验证代码:

package main

import (
	"bytes"
	"fmt"
	"github.com/imroc/req/v3"
)

func main() {
	var reqBuf, respBuf bytes.Buffer
	req.R().
		EnableDump().
		SetDumpOptions(&req.DumpOptions{
			RequestOutput:  &reqBuf,
			ResponseOutput: &respBuf,
			RequestHeader:  true,
			RequestBody:    true,
			ResponseHeader: true,
			ResponseBody:   true,
		}).
		MustGet("https://httpbin.org/gzip")
	fmt.Println("req content:")
	fmt.Println(reqBuf.String())
	fmt.Println("resp content:")
	fmt.Println(respBuf.String())
}

运行:

$ go run .
req content:
:authority: httpbin.org
:method: GET
:path: /gzip
:scheme: https
accept-encoding: gzip
user-agent: req/v3 (https://github.com/imroc/req)


resp content:
:status: 200
date: Mon, 17 Oct 2022 11:32:52 GMT
content-type: application/json
content-length: 224
server: gunicorn/19.9.0
content-encoding: gzip
access-control-allow-origin: *
access-control-allow-credentials: true

{
  "gzipped": true, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Host": "httpbin.org", 
    "User-Agent": "req/v3 (https://github.com/imroc/req)", 
    "X-Amzn-Trace-Id": "Root=1-634d3d64-225bcc6729505d2933dcd5a3"
  }, 
  "method": "GET", 
  "origin": "103.7.29.7"
}

imroc avatar Oct 17 '22 11:10 imroc

不知道为啥,单独拿代码放到test里运行,是成功解码的。但放到程序里时,没成功解码 image image

shadow1ng avatar Oct 17 '22 12:10 shadow1ng

看能否提取成公开可复现代码,这样好排查

imroc avatar Oct 17 '22 12:10 imroc

嗯嗯,我后续尝试弄弄

shadow1ng avatar Oct 17 '22 12:10 shadow1ng

关键点在这里:

r.Headers = Req.Header.Clone()

Req.Header 是用 http.ReadRequestreqtext 中解析出来的,而 reqtext 里包含了 Accept-Encoding 的 header,也就是说,显式给 Request 设置了 Accept-Encoding 这个 header,而显式设置 Accept-Encoding 意味着需要用户自行去解压缩。只有不显式设置 Accept-Encoding 才会自动解压缩,标准库也是这样的,你可以试下

imroc avatar Oct 18 '22 09:10 imroc

噢噢,那只要把Accept-Encoding: gzip, deflate去掉就行了咯?

shadow1ng avatar Oct 18 '22 09:10 shadow1ng

噢噢,那只要把Accept-Encoding: gzip, deflate去掉就行了咯?

是的

imroc avatar Oct 18 '22 09:10 imroc

好的,谢谢

shadow1ng avatar Oct 18 '22 09:10 shadow1ng