You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

70 lines
1.6 KiB

  1. package debug
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. "net/http/httputil"
  7. "os"
  8. )
  9. // DebugRequestTransport 会打印请求和响应信息, 方便调试.
  10. type DebugRequestTransport struct {
  11. RequestHeader bool
  12. RequestBody bool // RequestHeader 为 true 时,这个选项才会生效
  13. ResponseHeader bool
  14. ResponseBody bool // ResponseHeader 为 true 时,这个选项才会生效
  15. // debug 信息输出到 Writer 中, 默认是 os.Stderr
  16. Writer io.Writer
  17. Transport http.RoundTripper
  18. }
  19. // RoundTrip implements the RoundTripper interface.
  20. func (t *DebugRequestTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  21. req = cloneRequest(req) // per RoundTrip contract
  22. w := t.Writer
  23. if w == nil {
  24. w = os.Stderr
  25. }
  26. if t.RequestHeader {
  27. a, _ := httputil.DumpRequest(req, t.RequestBody)
  28. fmt.Fprintf(w, "%s\n\n", string(a))
  29. }
  30. resp, err := t.transport().RoundTrip(req)
  31. if err != nil {
  32. return resp, err
  33. }
  34. if t.ResponseHeader {
  35. b, _ := httputil.DumpResponse(resp, t.ResponseBody)
  36. fmt.Fprintf(w, "%s\n", string(b))
  37. }
  38. return resp, err
  39. }
  40. func (t *DebugRequestTransport) transport() http.RoundTripper {
  41. if t.Transport != nil {
  42. return t.Transport
  43. }
  44. return http.DefaultTransport
  45. }
  46. // cloneRequest returns a clone of the provided *http.Request. The clone is a
  47. // shallow copy of the struct and its Header map.
  48. func cloneRequest(r *http.Request) *http.Request {
  49. // shallow copy of the struct
  50. r2 := new(http.Request)
  51. *r2 = *r
  52. // deep copy of the Header
  53. r2.Header = make(http.Header, len(r.Header))
  54. for k, s := range r.Header {
  55. r2.Header[k] = append([]string(nil), s...)
  56. }
  57. return r2
  58. }