net/http Transport
$ go version go version go1.20.5 darwin/arm64 DefaultTransport 看一下 DefaultTransport 的 RoundTrip 方法。 1// src/net/http/roundtrip.go#L8 2// RoundTrip implements the RoundTripper interface. 3// 4// For higher-level HTTP client support (such as handling of cookies 5// and redirects), see Get, Post, and the Client type. 6// 7// Like the RoundTripper interface, the error types returned 8// by RoundTrip are unspecified. 9func (t *Transport) RoundTrip(req *Request) (*Response, error) { 10 return t.roundTrip(req) 11} 12 13// src/net/http/transport.go#L510 14// roundTrip implements a RoundTripper over HTTP. 15func (t *Transport) roundTrip(req *Request) (*Response, error) { 16 t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) 17 ctx := req.Context() 18 trace := httptrace.ContextClientTrace(ctx) 19 20 if req.URL == nil { 21 req.closeBody() 22 return nil, errors.New("http: nil Request.URL") 23 } 24 if req.Header == nil { 25 req.closeBody() 26 return nil, errors.New("http: nil Request.Header") 27 } 28 scheme := req.URL.Scheme 29 isHTTP := scheme == "http" || scheme == "https" 30 if isHTTP { 31 for k, vv := range req.Header { 32 if !httpguts.ValidHeaderFieldName(k) { 33 req.closeBody() 34 return nil, fmt.Errorf("net/http: invalid header field name %q", k) 35 } 36 for _, v := range vv { 37 if !httpguts.ValidHeaderFieldValue(v) { 38 req.closeBody() 39 // Don't include the value in the error, because it may be sensitive. 40 return nil, fmt.Errorf("net/http: invalid header field value for %q", k) 41 } 42 } 43 } 44 } 45 46 origReq := req 47 cancelKey := cancelKey{origReq} 48 req = setupRewindBody(req) 49 50 if altRT := t.alternateRoundTripper(req); altRT != nil { 51 if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol { 52 return resp, err 53 } 54 var err error 55 req, err = rewindBody(req) 56 if err != nil { 57 return nil, err 58 } 59 } 60 if !isHTTP { 61 req.closeBody() 62 return nil, badStringError("unsupported protocol scheme", scheme) 63 } 64 if req.Method != "" && !validMethod(req.Method) { 65 req.closeBody() 66 return nil, fmt.Errorf("net/http: invalid method %q", req.Method) 67 } 68 if req.URL.Host == "" { 69 req.closeBody() 70 return nil, errors.New("http: no Host in request URL") 71 } 72 73 for { 74 select { 75 case <-ctx.Done(): 76 req.closeBody() 77 return nil, ctx.Err() 78 default: 79 } 80 81 // treq gets modified by roundTrip, so we need to recreate for each retry. 82 treq := &transportRequest{Request: req, trace: trace, cancelKey: cancelKey} 83 cm, err := t.connectMethodForRequest(treq) 84 if err != nil { 85 req.closeBody() 86 return nil, err 87 } 88 89 // Get the cached or newly-created connection to either the 90 // host (for http or https), the http proxy, or the http proxy 91 // pre-CONNECTed to https server. In any case, we'll be ready 92 // to send it requests. 93 pconn, err := t.getConn(treq, cm) 94 if err != nil { 95 t.setReqCanceler(cancelKey, nil) 96 req.closeBody() 97 return nil, err 98 } 99 100 var resp *Response 101 if pconn.alt != nil { 102 // HTTP/2 path. 103 t.setReqCanceler(cancelKey, nil) // not cancelable with CancelRequest 104 resp, err = pconn.alt.RoundTrip(req) 105 } else { 106 resp, err = pconn.roundTrip(treq) 107 } 108 if err == nil { 109 resp.Request = origReq 110 return resp, nil 111 } 112 113 // Failed. Clean up and determine whether to retry. 114 if http2isNoCachedConnError(err) { 115 if t.removeIdleConn(pconn) { 116 t.decConnsPerHost(pconn.cacheKey) 117 } 118 } else if !pconn.shouldRetryRequest(req, err) { 119 // Issue 16465: return underlying net.Conn.Read error from peek, 120 // as we've historically done. 121 if e, ok := err.(nothingWrittenError); ok { 122 err = e.error 123 } 124 if e, ok := err.(transportReadFromServerError); ok { 125 err = e.err 126 } 127 return nil, err 128 } 129 testHookRoundTripRetried() 130 131 // Rewind the body if we're able to. 132 req, err = rewindBody(req) 133 if err != nil { 134 return nil, err 135 } 136 } 137} 因为 RoundTripper 说明了请求的 URL 和 Header 必须初始化,所以一开始检查报错。再往后,如果 schema 是 http 的话,检查了一下 header 的键值对的非法字符。再往后,注意到有一个 setupRewindBody,是用于恢复请求 body 的 ...