我有以下简单的http.Client
:
import (
"net/http"
"log"
)
...
func main() {
...
link = "http://example.com"
method = "GET"
req, _ := http.NewRequest(method, link, nil)
client := &http.Client{}
myZapLogger.Info("Sending a %s request to %sn", method, link)
resp, err := client.Do(req)
if err != nil {
myZapLogger.Error(..., err) // I'm logging rather than fatal-ing or so
} else {
myZapLogger.Info("Received a %d on request X", resp.StatusCode)
}
...
}
...
我正在寻找一种方法,通过钩子(或左右)为每个请求做上述操作,以便每次都自动触发。我可以写一个包含所有这些的函数,但是在我将http客户端传递给其他包的情况下,我将无法以这种方式控制/记录这样的请求(例如aws-go-sdk
)。
是否有一种方法可以通过上下文或附加钩子到客户端?
感谢的评论回答了这个问题;我把它写入code:
type MyRoundTripper struct {}
func (t MyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
// Do work before the request is sent
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
return resp, err
}
// Do work after the response is received
return resp, err
}
要使用它,只需将它传递给HTTP客户端:
rt := MyRoundTripper{}
client := http.Client{Transport: rt}
我已经混合了几个不同的地方,并提出了这个代码:
package matrix
import (
"bytes"
"mylogger/colorlogger"
"io"
"net/http"
)
func filterAuthorization(headers http.Header) http.Header {
filteredHeaders := make(http.Header)
for k, v := range headers {
if k == "Authorization" {
filteredHeaders[k] = []string{"<removed>"}
} else {
filteredHeaders[k] = v
}
}
return filteredHeaders
}
// https://stackoverflow.com/questions/23070876/reading-body-of-http-request-without-modifying-request-state
// https://stackoverflow.com/questions/69276445/logging-all-http-request-and-response-from-done-through-an-http-client
type MyRoundTripper struct{}
func (t MyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
var reqStr string
var respStr string
if req.Body != nil {
reqbuf, e := io.ReadAll(req.Body)
if e != nil {
colorlogger.Log.Fatal("Reading http response from RoundTrip injector error: ", e)
} else {
reqrdr1 := io.NopCloser(bytes.NewBuffer(reqbuf))
reqrdr2 := io.NopCloser(bytes.NewBuffer(reqbuf))
req.Body = reqrdr2
// read resp.Body to string
breq, errreq := io.ReadAll(reqrdr1)
if errreq != nil {
colorlogger.Log.Error("Reading http request from RoundTrip injector error: ", errreq)
} else {
reqStr = string(breq)
}
}
}
// Do work before the request is sent
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
return resp, err
}
if resp.Body != nil {
respbuf, e := io.ReadAll(resp.Body)
if e != nil {
colorlogger.Log.Fatal("Reading http response from RoundTrip injector error: ", e)
} else {
resprdr2 := io.NopCloser(bytes.NewBuffer(respbuf))
resp.Body = resprdr2
resprdr1 := io.NopCloser(bytes.NewBuffer(respbuf))
// read resp.Body to string
b, errresp := io.ReadAll(resprdr1)
if errresp != nil {
colorlogger.Log.Error("Reading http response from RoundTrip injector error: ", errresp)
} else {
respStr = string(b)
}
}
}
// Do work after the response is received
colorlogger.Log.Debugf("%sREQUEST(%s) %s, Headers: %+v, Body: %s, RESPONSE(%d), Headers: %+v, Body: %s%s",
colorlogger.Blue,
req.Method,
req.URL.Path,
filterAuthorization(req.Header),
reqStr,
resp.StatusCode,
resp.Header,
respStr,
colorlogger.CLR)
return resp, err
}
如下所示,它是这样整合的:
要使用它,只需将其传递给HTTP客户端:
rt:= MyRoundTripper{} client:= http。客户端{传输:rt}
注意:我可能会改变错误处理,因为致命的.
注意:我也喜欢https://medium.com/@motemen/add-a-single-line-to- go-source-and-track-every-http-requests-responses-37f2f15eb72f,但我希望能够在运行期间从调试更改为无调试。