{"id":46,"date":"2026-02-18T11:19:26","date_gmt":"2026-02-18T03:19:26","guid":{"rendered":"http:\/\/43.138.147.217\/?p=46"},"modified":"2026-02-18T11:19:26","modified_gmt":"2026-02-18T03:19:26","slug":"go%e5%bc%80%e5%8f%91%e4%bc%81%e4%b8%9a%e7%ba%a7%e5%be%ae%e6%9c%8d%e5%8a%a1%e7%bd%91%e5%85%b3%ef%bc%883%ef%bc%89golang-%e5%88%9b%e5%bb%ba-http-%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%92%8c%e5%ae%a2%e6%88%b7","status":"publish","type":"post","link":"https:\/\/fableary.top\/?p=46","title":{"rendered":"Go\u5f00\u53d1\u4f01\u4e1a\u7ea7\u5fae\u670d\u52a1\u7f51\u5173\uff083\uff09Golang \u521b\u5efa HTTP \u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef"},"content":{"rendered":"\n<p><strong>\u76ee\u5f55\uff1a<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u670d\u52a1\u7aef\u4ee3\u7801\u5c55\u793a<\/li>\n\n\n\n<li>\u5ba2\u6237\u7aef\u4ee3\u7801\u5c55\u793a<\/li>\n\n\n\n<li>HTTP \u670d\u52a1\u5668\u6e90\u7801\u89e3\u8bfb\n<ul class=\"wp-block-list\">\n<li>\u51fd\u6570\u662f\u4e00\u7b49\u516c\u6c11<\/li>\n\n\n\n<li>\u6ce8\u518c\u539f\u7406<\/li>\n\n\n\n<li>\u670d\u52a1\u542f\u52a8\u4e0e\u8bf7\u6c42\u5904\u7406\u6d41\u7a0b<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>HTTP \u5ba2\u6237\u7aef\u6e90\u7801\u89e3\u8bfb\n<ul class=\"wp-block-list\">\n<li>\u8bf7\u6c42\u6d41\u7a0b<\/li>\n\n\n\n<li>Transport RoundTrip \u6d41\u7a0b<\/li>\n\n\n\n<li><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>\u670d\u52a1\u7aef\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"log\"\n\t\"net\/http\"\n\t\"time\"\n)\n\nvar (\n\tAddr = \":1210\"\n)\n\nfunc main() {\n\t\/\/ \u521b\u5efa\u8def\u7531\u5668\n\tmux := http.NewServeMux()\n\t\/\/ \u8bbe\u7f6e\u8def\u7531\u89c4\u5219\n\tmux.HandleFunc(\"\/bye\", sayBye)\n\t\/\/ \u521b\u5efa\u670d\u52a1\u5668\n\tserver := &amp;http.Server{\n\t\tAddr:         Addr,\n\t\tWriteTimeout: time.Second * 3,\n\t\tHandler:      mux,\n\t}\n\t\/\/ \u76d1\u542c\u7aef\u53e3\u5e76\u63d0\u4f9b\u670d\u52a1\n\tlog.Println(\"Starting httpserver at \" + Addr)\n\tlog.Fatal(server.ListenAndServe())\n}\n\nfunc sayBye(w http.ResponseWriter, r *http.Request) {\n\ttime.Sleep(1 * time.Second)\n\tw.Write(&#091;]byte(\"bye bye, this is httpServer\"))\n}\n<\/code><\/pre>\n\n\n\n<p>\u5ba2\u6237\u7aef\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"io\/ioutil\"\n\t\"net\"\n\t\"net\/http\"\n\t\"time\"\n)\n\nfunc main() {\n\t\/\/ \u521b\u5efa\u8fde\u63a5\u6c60\n\ttransport := &amp;http.Transport{\n\t\tDialContext: (&amp;net.Dialer{\n\t\t\tTimeout:   30 * time.Second, \/\/ \u8fde\u63a5\u8d85\u65f6\n\t\t\tKeepAlive: 30 * time.Second, \/\/ \u957f\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4\n\t\t}).DialContext,\n\t\tMaxIdleConns:          100,              \/\/ \u6700\u5927\u7a7a\u95f2\u8fde\u63a5\n\t\tIdleConnTimeout:       90 * time.Second, \/\/ \u7a7a\u95f2\u8d85\u65f6\u65f6\u95f4\n\t\tTLSHandshakeTimeout:   10 * time.Second, \/\/ tls\u63e1\u624b\u8d85\u65f6\u65f6\u95f4\n\t\tExpectContinueTimeout: 1 * time.Second,  \/\/ 100-continue\u72b6\u6001\u7801\u8d85\u65f6\u65f6\u95f4\n\t}\n\t\/\/ \u521b\u5efa\u5ba2\u6237\u7aef\n\tclient := &amp;http.Client{\n\t\tTimeout:   30 * time.Second, \/\/ \u8bf7\u6c42\u8d85\u65f6\u65f6\u95f4\n\t\tTransport: transport,\n\t}\n\t\/\/ \u8bf7\u6c42\u6570\u636e\n\tresp, err := client.Get(\"http:\/\/127.0.0.1:1210\/bye\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n\t\/\/ \u8bfb\u53d6\u5185\u5bb9\n\tbds, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(string(bds))\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">HTTP \u670d\u52a1\u5668\u6e90\u7801\u89e3\u8bfb<\/h3>\n\n\n\n<p><strong>HTTP\u662f\u5de5\u4f5c\u4e2d\u6700\u5e38\u63a5\u89e6\u7684\u534f\u8bae<\/strong><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u51fd\u6570\u662f\u4e00\u7b49\u516c\u6c11<\/h4>\n\n\n\n<p>\u628a\u51fd\u6570\u4f5c\u4e3a\u4e00\u79cd\u6570\u636e\u7c7b\u578b\u53bb\u4f20\u9012\uff0c\u53bb\u5b9e\u73b0\u51fd\u6570\u7684\u56de\u8c03\uff08\u533f\u540d\u51fd\u6570\u3001\u95ed\u5305\uff09<\/p>\n\n\n\n<p>\u8fd9\u79cd\u5b9a\u4e49\u53ef\u4ee5\u5c06\u666e\u901a\u51fd\u6570\u5305\u88c5\u6210\u5b9e\u73b0 http.Handler \u63a5\u53e3\u7684\u5bf9\u8c61<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u6ce8\u518c\u539f\u7406<\/h4>\n\n\n\n<p>\u672c\u8d28\u4e0a\u662f\u6709\u8fd9\u6837\u4e00\u4e2a\u7ed3\u6784\u4f53\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>type ServeMux struct {\n\tmu     sync.RWMutex\n\ttree   routingNode\n\tindex  routingIndex\n\tmux121 serveMux121 \/\/ used only when GODEBUG=httpmuxgo121=1\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ A routingNode is a node in the decision tree.\n\/\/ The same struct is used for leaf and interior nodes.\ntype routingNode struct {\n\t\/\/ A leaf node holds a single pattern and the Handler it was registered\n\t\/\/ with.\n\tpattern *pattern\n\thandler Handler\n\n\t\/\/ An interior node maps parts of the incoming request to child nodes.\n\t\/\/ special children keys:\n\t\/\/     \"\/\"\ttrailing slash (resulting from {$})\n\t\/\/\t   \"\"   single wildcard\n\tchildren   mapping&#091;string, *routingNode]\n\tmultiChild *routingNode \/\/ child with multi wildcard\n\temptyChild *routingNode \/\/ optimization: child with key \"\"\n}<\/code><\/pre>\n\n\n\n<p>\u90a3\u6ce8\u518c\u8def\u7531\u7684\u8fc7\u7a0b\u5b9e\u9645\u4e0a\u4f20\u5165\u7684\u5c31\u662f\u4e00\u4e2a pattern \u548c\u4e00\u4e2a handler \u65b9\u6cd5\u3002<\/p>\n\n\n\n<p>\u5185\u90e8\u7684\u672c\u8d28\u5b9e\u73b0\u5c31\u662f\u5411\u8fd9\u4e2a\u6811\u5f62\u7ed3\u6784\u91cc\u63d2\u5165\u8282\u70b9\uff1a<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>\u5148\u6309\u00a0<strong>host<\/strong>\uff08\u5982\u679c\u6709\uff09\u6dfb\u52a0\u5b50\u8282\u70b9\u3002<\/li>\n\n\n\n<li>\u518d\u6309\u00a0<strong>method<\/strong>\uff08\u5982\u00a0<code>GET<\/code>\u3001<code>POST<\/code>\u00a0\u6216\u7a7a\u5b57\u7b26\u4e32\u8868\u793a\u4efb\u610f\u65b9\u6cd5\uff09\u6dfb\u52a0\u5b50\u8282\u70b9\u3002<\/li>\n\n\n\n<li>\u6700\u540e\u6309\u8def\u5f84\u7684\u00a0<strong>segments<\/strong>\u00a0\u9010\u5c42\u6dfb\u52a0\uff0c\u5e76\u5728\u53f6\u5b50\u8282\u70b9\u5b58\u50a8\u00a0<code>pattern<\/code>\u00a0\u548c\u00a0<code>handler<\/code>\u3002<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>func (root *routingNode) addPattern(p *pattern, h Handler) {\n\t\/\/ First level of tree is host.\n\tn := root.addChild(p.host)\n\t\/\/ Second level of tree is method.\n\tn = n.addChild(p.method)\n\t\/\/ Remaining levels are path.\n\tn.addSegments(p.segments, p, h)\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">\u670d\u52a1\u542f\u52a8\u4e0e\u8bf7\u6c42\u5904\u7406\u6d41\u7a0b<\/h4>\n\n\n\n<p><strong>\u542f\u52a8\u76d1\u542c<\/strong>\uff1a\u8c03\u7528\u00a0<code>s.ListenAndServe()<\/code><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u786e\u5b9a\u76d1\u542c\u5730\u5740\uff08\u9ed8\u8ba4\u00a0<code>:http<\/code>\u00a0\u5373 80 \u7aef\u53e3\uff09<\/li>\n\n\n\n<li>\u521b\u5efa TCP \u76d1\u542c\u5668\u00a0<code>ln<\/code><\/li>\n\n\n\n<li>\u5c06\u76d1\u542c\u5668\u4ea4\u7ed9\u00a0<code>s.Serve(ln)<\/code>\u00a0\u8fdb\u4e00\u6b65\u5904\u7406<\/li>\n<\/ol>\n\n\n\n<p><strong>\u63a5\u53d7\u8fde\u63a5<\/strong>\uff1a<code>s.Serve(ln)<\/code>\u00a0\u5faa\u73af\u8c03\u7528\u00a0<code>ln.Accept()<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>for {\n    rw, err := l.Accept()\n    \/\/ \u6bcf\u4e2a\u65b0\u8fde\u63a5\u521b\u5efa\u4e00\u4e2a goroutine \u5904\u7406\n    go (c *conn).serve(ctx)\n}<\/code><\/pre>\n\n\n\n<p>\u6bcf\u4e2a\u8fde\u63a5\u72ec\u7acb\u5e76\u53d1\u5904\u7406\u3002<\/p>\n\n\n\n<p><strong>\u5904\u7406\u8fde\u63a5<\/strong>\uff1a<code>c.serve()<\/code>\u00a0\u5185\u90e8\u5faa\u73af\u8bfb\u53d6\u8bf7\u6c42\u5e76\u8c03\u7528 handler<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8bfb\u53d6 HTTP \u8bf7\u6c42\uff0c\u6784\u9020\u00a0<code>ResponseWriter<\/code>\u00a0\u548c\u00a0<code>Request<\/code><\/li>\n\n\n\n<li>\u8c03\u7528\u00a0<code>serverHandler{c.server}.ServeHTTP(w, req)<\/code>\u00a0\u627e\u5230\u5e76\u6267\u884c\u5b9e\u9645\u5904\u7406\u51fd\u6570<\/li>\n<\/ul>\n\n\n\n<p><strong>\u8def\u7531\u5230\u6700\u7ec8 handler<\/strong>\uff1a<code>serverHandler.ServeHTTP<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {\n    handler := sh.srv.Handler\n    if handler == nil {\n        handler = DefaultServeMux   \/\/ \u9ed8\u8ba4\u4f7f\u7528\u6807\u51c6\u5e93\u7684\u8def\u7531\u5668\n    }\n    \/\/ \u7279\u6b8a\u5904\u7406 OPTIONS * \u8bf7\u6c42\n    handler.ServeHTTP(rw, req)\n}<\/code><\/pre>\n\n\n\n<p>\u5982\u679c\u7528\u6237\u8bbe\u7f6e\u4e86\u81ea\u5b9a\u4e49\u00a0<code>Server.Handler<\/code>\uff0c\u5219\u4f7f\u7528\u4e4b\uff1b\u5426\u5219\u4f7f\u7528\u00a0<code>DefaultServeMux<\/code>\uff08\u5b83\u5b9e\u73b0\u4e86\u8def\u7531\u89c4\u5219\u5339\u914d\uff09\u3002<\/p>\n\n\n\n<p><strong>\u6700\u7ec8\u54cd\u5e94<\/strong>\uff1ahandler \u5904\u7406\u5b8c\u8bf7\u6c42\u540e\uff0c\u901a\u8fc7\u00a0<code>ResponseWriter<\/code>\u00a0\u8fd4\u56de\u6570\u636e\uff0c\u8fde\u63a5\u5173\u95ed\u6216\u590d\u7528\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">HTTP \u5ba2\u6237\u7aef\u6e90\u7801\u89e3\u8bfb<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">\u8bf7\u6c42\u6d41\u7a0b<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>Timeout<\/code><\/strong>\uff1a\u4ece\u8fde\u63a5\u5efa\u7acb\u5230\u8bfb\u5b8c\u54cd\u5e94\u4f53\u7684\u603b\u8d85\u65f6\uff0c\u96f6\u503c\u8868\u793a\u4e0d\u8bbe\u8d85\u65f6\uff08\u53ef\u80fd\u6c38\u4e45\u963b\u585e\uff09\u3002<\/li>\n\n\n\n<li><strong><code>Transport<\/code><\/strong>\uff1a\u771f\u6b63\u6267\u884c\u7f51\u7edc\u901a\u4fe1\u7684\u63a5\u53e3\uff08<code>http.RoundTripper<\/code>\uff09\uff0c\u9ed8\u8ba4\u5b9e\u73b0\u652f\u6301\u8fde\u63a5\u6c60\u3001TLS \u914d\u7f6e\u7b49\u3002<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>\tclient := &amp;http.Client{\n\t\tTimeout:   30 * time.Second, \/\/ \u8bf7\u6c42\u8d85\u65f6\u65f6\u95f4\n\t\tTransport: transport,\n\t}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>NewRequest<\/code>\u00a0\u6784\u9020\u4e00\u4e2a\u00a0<code>http.Request<\/code>\uff0c\u5305\u542b\u65b9\u6cd5\u3001URL\u3001\u53ef\u9009\u7684 body\u3002<\/li>\n\n\n\n<li>\u5b9e\u9645\u5904\u7406\u4ea4\u7ed9\u00a0<code>Do<\/code>\u00a0\u65b9\u6cd5\uff0c\u4ee5\u4fbf\u7edf\u4e00\u5904\u7406\u6240\u6709 HTTP \u65b9\u6cd5\u3002<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>func (c *Client) Get(url string) (resp *Response, err error) {\n\treq, err := NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.Do(req)\n}<\/code><\/pre>\n\n\n\n<p><code>Do<\/code>\u00a0\u672c\u8eab\u53ea\u662f\u52a0\u4e86\u4e00\u4e9b\u6587\u6863\u8bf4\u660e\u548c\u6821\u9a8c\uff0c\u6838\u5fc3\u903b\u8f91\u5728\u00a0<code>do<\/code>\u00a0\u65b9\u6cd5\u4e2d\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func (c *Client) Do(req *Request) (*Response, error) {\n\treturn c.do(req)\n}<\/code><\/pre>\n\n\n\n<p>\u65e0\u9650\u5faa\u73af\uff0c\u5b9e\u73b0\u53d1\u9001\u64cd\u4f5c\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if resp, didTimeout, err = c.send(req, deadline); err != nil {\n\t\t\t\/\/ c.send() always closes req.Body\n\t\t\treqBodyClosed = true\n\t\t\tif !deadline.IsZero() &amp;&amp; didTimeout() {\n\t\t\t\terr = &amp;timeoutError{err.Error() + \" (Client.Timeout exceeded while awaiting headers)\"}\n\t\t\t}\n\t\t\treturn nil, uerr(err)\n\t\t}<\/code><\/pre>\n\n\n\n<p>\u5177\u4f53\u7684 send \u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {\n\tif c.Jar != nil {\n\t\tfor _, cookie := range c.Jar.Cookies(req.URL) {\n\t\t\treq.AddCookie(cookie)\n\t\t}\n\t}\n\tresp, didTimeout, err = send(req, c.transport(), deadline)\n\tif err != nil {\n\t\treturn nil, didTimeout, err\n\t}\n\tif c.Jar != nil {\n\t\tif rc := resp.Cookies(); len(rc) &gt; 0 {\n\t\t\tc.Jar.SetCookies(req.URL, rc)\n\t\t}\n\t}\n\treturn resp, nil, nil\n}<\/code><\/pre>\n\n\n\n<p>\u5728\u66f4\u5185\u90e8\u7684 send \u51fd\u6570\u4e2d\uff08p.s \u600e\u4e48\u8fd9\u4e48\u591a\u5c42\uff09\u53bb\u8c03\u7528 RoundTrip \u65b9\u6cd5\u4ee5\u5f97\u5230 resp \uff0c\u5e76\u6700\u7ec8\u9010\u5c42\u8fd4\u56de\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resp, err = rt.RoundTrip(req)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Transport RoundTrip \u6d41\u7a0b<\/h4>\n\n\n\n<p>RoundTrip \u662f transport.go \u4e2d\u7684 <code>func (t *Transport) roundTrip(req *Request) (_ *Response, err error)<\/code> \u65b9\u6cd5<\/p>\n\n\n\n<p>\u5728\u5176\u4e2d\u5148\u6267\u884c getConn \u65b9\u6cd5\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u5c1d\u8bd5\u62ff\u53bb\u7a7a\u95f2\u94fe\u63a5<br><code>\u00a0 \u00a0 \/\/ Queue for idle connection.<\/code><br><code>\u00a0 \u00a0 if delivered := t.queueForIdleConn(w); !delivered {<br>\u00a0 \u00a0 \u00a0 \u00a0 t.queueForDial(w)<br>\u00a0 \u00a0 }<\/code><\/li>\n\n\n\n<li>\u5982\u679c\u62ff\u4e0d\u5230\u8fdb\u5165 select \u5e76\u7b49\u5f85\u5b8c\u6210\u6216\u8005\u53d6\u6d88<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Wait for completion or cancellation.\n\tselect {\n\tcase r := &lt;-w.result:\n\t\t\/\/ Trace success but only for HTTP\/1.\n\t\t\/\/ HTTP\/2 calls trace.GotConn itself.\n\t\tif r.pc != nil &amp;&amp; r.pc.alt == nil &amp;&amp; trace != nil &amp;&amp; trace.GotConn != nil {\n\t\t\tinfo := httptrace.GotConnInfo{\n\t\t\t\tConn:   r.pc.conn,\n\t\t\t\tReused: r.pc.isReused(),\n\t\t\t}\n\t\t\tif !r.idleAt.IsZero() {\n\t\t\t\tinfo.WasIdle = true\n\t\t\t\tinfo.IdleTime = time.Since(r.idleAt)\n\t\t\t}\n\t\t\ttrace.GotConn(info)\n\t\t}\n\t\tif r.err != nil {\n\t\t\t\/\/ If the request has been canceled, that's probably\n\t\t\t\/\/ what caused r.err; if so, prefer to return the\n\t\t\t\/\/ cancellation error (see golang.org\/issue\/16049).\n\t\t\tselect {\n\t\t\tcase &lt;-treq.ctx.Done():\n\t\t\t\terr := context.Cause(treq.ctx)\n\t\t\t\tif err == errRequestCanceled {\n\t\t\t\t\terr = errRequestCanceledConn\n\t\t\t\t}\n\t\t\t\treturn nil, err\n\t\t\tdefault:\n\t\t\t\t\/\/ return below\n\t\t\t}\n\t\t}\n\t\treturn r.pc, r.err\n\tcase &lt;-treq.ctx.Done():\n\t\terr := context.Cause(treq.ctx)\n\t\tif err == errRequestCanceled {\n\t\t\terr = errRequestCanceledConn\n\t\t}\n\t\treturn nil, err\n\t}<\/code><\/pre>\n\n\n\n<p>\u8fd9\u6bb5\u4ee3\u7801\u7684\u6838\u5fc3\u662f\u00a0<strong>\u201c\u4f18\u5148\u8fd4\u56de\u6700\u51c6\u786e\u7684\u9519\u8bef\u201d<\/strong>\u3002\u5b83\u786e\u4fdd\u4e86\u5728\u8bf7\u6c42\u88ab\u53d6\u6d88\u65f6\uff0c\u8c03\u7528\u65b9\u603b\u80fd\u6536\u5230\u00a0<code>context.Canceled<\/code>\u00a0\u6216\u00a0<code>context.DeadlineExceeded<\/code>\u00a0\u8fd9\u7c7b\u660e\u786e\u7684\u9519\u8bef\uff0c\u800c\u4e0d\u662f\u5728\u7f51\u7edc\u5c42\u88ab\u5305\u88c5\u8fc7\u7684\u5176\u4ed6\u9519\u8bef\u3002<\/p>\n\n\n\n<p>\u800c\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u5c31\u5b9e\u73b0\u4e86\u6700\u7ec8\u5f97\u5230\u8fde\u63a5\u7684\u8fc7\u7a0b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\t\/\/ Get the cached or newly-created connection to either the\n\t\t\/\/ host (for http or https), the http proxy, or the http proxy\n\t\t\/\/ pre-CONNECTed to https server. In any case, we'll be ready\n\t\t\/\/ to send it requests.\n\t\tpconn, err := t.getConn(treq, cm)\n\t\tif err != nil {\n\t\t\treq.closeBody()\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvar resp *Response\n\t\tif pconn.alt != nil {\n\t\t\t\/\/ HTTP\/2 path.\n\t\t\tresp, err = pconn.alt.RoundTrip(req)\n\t\t} else {\n\t\t\tresp, err = pconn.roundTrip(treq)\n\t\t}\n\t\tif err == nil {\n\t\t\tif pconn.alt != nil {\n\t\t\t\t\/\/ HTTP\/2 requests are not cancelable with CancelRequest,\n\t\t\t\t\/\/ so we have no further need for the request context.\n\t\t\t\t\/\/\n\t\t\t\t\/\/ On the HTTP\/1 path, roundTrip takes responsibility for\n\t\t\t\t\/\/ canceling the context after the response body is read.\n\t\t\t\tcancel(errRequestDone)\n\t\t\t}\n\t\t\tresp.Request = origReq\n\t\t\treturn resp, nil\n\t\t}\n\n\t\t\/\/ Failed. Clean up and determine whether to retry.\n\t\tif http2isNoCachedConnError(err) {\n\t\t\tif t.removeIdleConn(pconn) {\n\t\t\t\tt.decConnsPerHost(pconn.cacheKey)\n\t\t\t}\n\t\t} else if !pconn.shouldRetryRequest(req, err) {\n\t\t\t\/\/ Issue 16465: return underlying net.Conn.Read error from peek,\n\t\t\t\/\/ as we've historically done.\n\t\t\tif e, ok := err.(nothingWrittenError); ok {\n\t\t\t\terr = e.error\n\t\t\t}\n\t\t\tif e, ok := err.(transportReadFromServerError); ok {\n\t\t\t\terr = e.err\n\t\t\t}\n\t\t\tif b, ok := req.Body.(*readTrackingBody); ok &amp;&amp; !b.didClose {\n\t\t\t\t\/\/ Issue 49621: Close the request body if pconn.roundTrip\n\t\t\t\t\/\/ didn't do so already. This can happen if the pconn\n\t\t\t\t\/\/ write loop exits without reading the write request.\n\t\t\t\treq.closeBody()\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\ttestHookRoundTripRetried()\n\n\t\t\/\/ Rewind the body if we're able to.\n\t\treq, err = rewindBody(req)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}<\/code><\/pre>\n\n\n\n<p>\u4e0a\u9762\u662f HTTP\/2 \u7684\u5b9e\u73b0\u6d41\u7a0b\uff0c\u5728 HTTP\/1.X \u4e2d\u7a0d\u6709\u533a\u522b\u3002\u5b8c\u6210\u6d41\u7a0b\u56fe\u53c2\u8003\u5982\u4e0b\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"414\" height=\"853\" src=\"http:\/\/43.138.147.217\/wp-content\/uploads\/2026\/02\/image-5.png\" alt=\"\" class=\"wp-image-47\" srcset=\"https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-5.png 414w, https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-5-146x300.png 146w\" sizes=\"auto, (max-width: 414px) 100vw, 414px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Client \u3001Transport \u914d\u7f6e<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>transport := &amp;http.Transport{\n\t\tDialContext: (&amp;net.Dialer{\n\t\t\tTimeout:   30 * time.Second, \/\/ \u8fde\u63a5\u8d85\u65f6\n\t\t\tKeepAlive: 30 * time.Second, \/\/ \u957f\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4\n\t\t}).DialContext,\n\t\tMaxIdleConns:          100,              \/\/ \u6700\u5927\u7a7a\u95f2\u8fde\u63a5\n\t\tIdleConnTimeout:       90 * time.Second, \/\/ \u7a7a\u95f2\u8d85\u65f6\u65f6\u95f4\n\t\tTLSHandshakeTimeout:   10 * time.Second, \/\/ tls\u63e1\u624b\u8d85\u65f6\u65f6\u95f4\n\t\tExpectContinueTimeout: 1 * time.Second,  \/\/ 100-continue\u72b6\u6001\u7801\u8d85\u65f6\u65f6\u95f4\n\t}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"286\" src=\"http:\/\/43.138.147.217\/wp-content\/uploads\/2026\/02\/image-6-1024x286.png\" alt=\"\" class=\"wp-image-48\" srcset=\"https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-6-1024x286.png 1024w, https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-6-300x84.png 300w, https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-6-768x214.png 768w, https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-6-1536x429.png 1536w, https:\/\/fableary.top\/wp-content\/uploads\/2026\/02\/image-6.png 1608w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\u4ece&nbsp;<code>Client.Do<\/code>&nbsp;\u5f00\u59cb\uff0c\u5230\u8bf7\u6c42\u7ed3\u675f\uff08\u8fde\u63a5\u8fdb\u5165\u7a7a\u95f2\u72b6\u6001\uff09\uff0c\u6574\u4e2a\u8fc7\u7a0b\u53ef\u4ee5\u62c6\u89e3\u4e3a\u4ee5\u4e0b\u5173\u952e\u9636\u6bb5\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>Client.Do<\/code><\/strong>\uff1a\u6574\u4e2a\u8bf7\u6c42\u7684\u8d77\u59cb\u70b9\uff0c\u5bf9\u5e94\u603b\u8d85\u65f6\u3002<\/li>\n\n\n\n<li><strong><code>Dial<\/code><\/strong>\uff1a\u5efa\u7acb TCP \u8fde\u63a5\u3002<\/li>\n\n\n\n<li><strong><code>TLS handshake<\/code><\/strong>\uff1a\u5982\u679c\u4f7f\u7528 HTTPS\uff0c\u8fdb\u884c TLS \u63e1\u624b\u3002<\/li>\n\n\n\n<li><strong><code>Request<\/code><\/strong>\uff1a\u53d1\u9001 HTTP \u8bf7\u6c42\u5934\u90e8\u548c\u6b63\u6587\uff08\u5982\u679c\u6709\uff09\u3002<\/li>\n\n\n\n<li><strong><code>Resp. headers<\/code><\/strong>\uff1a\u8bfb\u53d6\u670d\u52a1\u5668\u8fd4\u56de\u7684\u54cd\u5e94\u5934\u90e8\u3002<\/li>\n\n\n\n<li><strong><code>Response body<\/code><\/strong>\uff1a\u8bfb\u53d6\u54cd\u5e94\u6b63\u6587\u3002<\/li>\n\n\n\n<li><strong><code>Idle<\/code><\/strong>\uff1a\u8bf7\u6c42\u5b8c\u6210\u540e\uff0c\u8fde\u63a5\u8fdb\u5165\u7a7a\u95f2\u72b6\u6001\uff0c\u7b49\u5f85\u590d\u7528\u3002<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">\u9636\u6bb5<\/th><th class=\"has-text-align-left\" data-align=\"left\">\u5bf9\u5e94\u8d85\u65f6\u5b57\u6bb5<\/th><th class=\"has-text-align-left\" data-align=\"left\">\u8bf4\u660e<\/th><\/tr><\/thead><tbody><tr><td><strong>\u6574\u4e2a\u8bf7\u6c42<\/strong><\/td><td><code>http.Client.Timeout<\/code><\/td><td>\u4ece&nbsp;<code>Client.Do<\/code>&nbsp;\u5f00\u59cb\uff0c\u5230\u8bfb\u5b8c\u54cd\u5e94\u6b63\u6587\u7684\u603b\u65f6\u95f4\u3002\u5982\u679c\u8d85\u65f6\uff0c\u8bf7\u6c42\u4f1a\u88ab\u53d6\u6d88\u3002<\/td><\/tr><tr><td><strong>TCP \u8fde\u63a5\u5efa\u7acb<\/strong><\/td><td><code>net.Dialer.Timeout<\/code><\/td><td>\u5efa\u7acb TCP \u8fde\u63a5\u7684\u6700\u5927\u7b49\u5f85\u65f6\u95f4\uff08\u5305\u62ec\u57df\u540d\u89e3\u6790\uff09\u3002<\/td><\/tr><tr><td><strong>TLS \u63e1\u624b<\/strong><\/td><td><code>http.Transport.TLSHandshakeTimeout<\/code><\/td><td>HTTPS \u8bf7\u6c42\u4e2d\uff0cTLS \u63e1\u624b\u5141\u8bb8\u7684\u6700\u5927\u65f6\u95f4\u3002<\/td><\/tr><tr><td><strong>\u53d1\u9001\u8bf7\u6c42<\/strong><\/td><td>\uff08\u65e0\u72ec\u7acb\u8d85\u65f6\uff09<\/td><td>Go \u6ca1\u6709\u5355\u72ec\u7684\u201c\u8bf7\u6c42\u53d1\u9001\u201d\u8d85\u65f6\uff0c\u53d1\u9001\u8fc7\u7a0b\u901a\u5e38\u5f88\u5feb\uff0c\u4f46\u5982\u679c\u7f51\u7edc\u963b\u585e\uff0c\u53ef\u80fd\u53d7\u5e95\u5c42 TCP \u5199\u8d85\u65f6\u5f71\u54cd\uff0c\u4f46\u4e00\u822c\u4e0d\u5355\u72ec\u8bbe\u7f6e\u3002<\/td><\/tr><tr><td><strong>\u8bfb\u53d6\u54cd\u5e94\u5934<\/strong><\/td><td><code>http.Transport.ResponseHeaderTimeout<\/code><\/td><td>\u4ece\u5199\u5b8c\u8bf7\u6c42\u5230\u8bfb\u5b8c\u54cd\u5e94\u5934\u90e8\u5141\u8bb8\u7684\u6700\u5927\u65f6\u95f4\u3002\u5982\u679c\u670d\u52a1\u5668\u54cd\u5e94\u6162\uff0c\u6b64\u8d85\u65f6\u751f\u6548\u3002<\/td><\/tr><tr><td><strong>\u8bfb\u53d6\u54cd\u5e94\u4f53<\/strong><\/td><td>\uff08\u65e0\u72ec\u7acb\u8d85\u65f6\uff09<\/td><td>\u8bfb\u53d6\u6b63\u6587\u6ca1\u6709\u72ec\u7acb\u8d85\u65f6\uff0c\u4f46\u53ef\u4ee5\u901a\u8fc7&nbsp;<code>Client.Timeout<\/code>&nbsp;\u6574\u4f53\u63a7\u5236\uff0c\u6216\u901a\u8fc7&nbsp;<code>context.WithTimeout<\/code>&nbsp;\u5728\u8bf7\u6c42\u7ea7\u522b\u8bbe\u7f6e\u66f4\u7ec6\u7c92\u5ea6\u7684\u8d85\u65f6\u3002<\/td><\/tr><tr><td><strong>\u8fde\u63a5\u7a7a\u95f2<\/strong><\/td><td><code>http.Transport.IdleConnTimeout<\/code><\/td><td>\u8fde\u63a5\u5728\u8fde\u63a5\u6c60\u4e2d\u4fdd\u6301\u7a7a\u95f2\u7684\u6700\u5927\u65f6\u95f4\uff0c\u8d85\u65f6\u540e\u4f1a\u88ab\u5173\u95ed\u3002<\/td><\/tr><\/tbody><\/table><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\u76ee\u5f55\uff1a \u670d\u52a1\u7aef\u4ee3\u7801\u5982\u4e0b\uff1a \u5ba2\u6237\u7aef\u4ee3\u7801\u5982\u4e0b\uff1a HTTP \u670d\u52a1\u5668\u6e90\u7801\u89e3\u8bfb HTTP\u662f\u5de5\u4f5c\u4e2d\u6700\u5e38\u63a5\u89e6\u7684\u534f\u8bae \u51fd\u6570\u662f\u4e00 &#8230; <a title=\"Go\u5f00\u53d1\u4f01\u4e1a\u7ea7\u5fae\u670d\u52a1\u7f51\u5173\uff083\uff09Golang \u521b\u5efa HTTP \u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\" class=\"read-more\" href=\"https:\/\/fableary.top\/?p=46\" aria-label=\"\u9605\u8bfb Go\u5f00\u53d1\u4f01\u4e1a\u7ea7\u5fae\u670d\u52a1\u7f51\u5173\uff083\uff09Golang \u521b\u5efa HTTP \u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\">\u9605\u8bfb\u66f4\u591a<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-46","post","type-post","status-publish","format-standard","hentry","category-gogateway"],"_links":{"self":[{"href":"https:\/\/fableary.top\/index.php?rest_route=\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fableary.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fableary.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fableary.top\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/fableary.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=46"}],"version-history":[{"count":1,"href":"https:\/\/fableary.top\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/fableary.top\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions\/49"}],"wp:attachment":[{"href":"https:\/\/fableary.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fableary.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fableary.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}