Parsing Go's http client
The following tutorial column will introduce you to the http client of Go. I hope it will be helpful to friends who need it!
go encapsulates the http client, and it is very convenient to request remote data. Let’s take a look at how to implement it at the bottom of the source code. resp, err := http.Get("https://baidu.com") if err != nil {
fmt.Printf("发起请求失败:%v", err)
return }defer resp.Body.Close() io.Copy(os.Stdout, resp.Body)
Copy after loginThe general process of the request
resp, err := http.Get("https://baidu.com") if err != nil { fmt.Printf("发起请求失败:%v", err) return }defer resp.Body.Close() io.Copy(os.Stdout, resp.Body)
1. Construct the request object according to the request conditions
2. All client requests , will be processed by client.do()
func (c *Client) do(req *Request) (retres *Response, reterr error)
2.1 request request is processed by client.send()
func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error)resp, didTimeout, err = send(req, c.transport(), deadline)//默认传DefaultTransport
3.send function
func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) { resp, err = rt.RoundTrip(req) }
4. The RoundTrip method of DefaultTransport is actually the RoundTrip method of Transport
func (t *Transport) roundTrip(req *Request) (*Response, error) { treq := &transportRequest{Request: req, trace: trace} //封装新的request cm, err := t.connectMethodForRequest(treq) pconn, err := t.getConn(treq, cm) //使用连接池技术,获取连接对象*persistConn, resp, err = pconn.roundTrip(treq) //使用连接对象获取response}
5. Use connection pool technology to obtain the connection object *persistConn
func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) { w := &wantConn{ //构建连接对象 cm: cm, key: cm.key(), ctx: ctx, ready: make(chan struct{}, 1), beforeDial: testHookPrePendingDial, afterDial: testHookPostPendingDial, } if delivered := t.queueForIdleConn(w); delivered {//从连接池获取符合的连接对象,有就返回 pc := w.pc return pc, nil } t.queueForDial(w)//发起连接 select { case <-w.ready: //连接准备好,就返回连接对象 return w.pc, w.err}
5.1 Transport.queueForDial initiates connection
func (t *Transport) queueForDial(w *wantConn) { go t.dialConnFor(w)}
5.2 Initiates dialing dialConnFor
func (t *Transport) dialConnFor(w *wantConn) { pc, err := t.dialConn(w.ctx, w.cm) //发起拨号,返回连接对象 delivered := w.tryDeliver(pc, err)}
5.3 Initiate dialing
func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) { pconn = &persistConn{ //构建连接对象 t: t, cacheKey: cm.key(), reqch: make(chan requestAndChan, 1), writech: make(chan writeRequest, 1), closech: make(chan struct{}), writeErrCh: make(chan error, 1), writeLoopDone: make(chan struct{}), } conn, err := t.dial(ctx, "tcp", cm.addr()) //tcp连接,获取到net.conn对象 pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())//可以从conn读 pconn.bw = bufio.NewWriterSize(persistConnWriter{pconn}, t.writeBufferSize())//写到conn go pconn.readLoop()//开启读协程 go pconn.writeLoop()//开启写协程 return pconn, nil}
5.4 Reading the coroutine, although it is a for loop, the requested response is read in one go. If it is not closed, the coroutine will be leaked
func (pc *persistConn) readLoop() { alive := true for alive { rc := <-pc.reqch //读取request,写入的地方在步骤6 resp, err = pc.readResponse(rc, trace) //返回response //response的body是否可写,服务器code101才可写,所以正常这个是false bodyWritable := resp.bodyIsWritable() //response.Close设置循环结束,退出协程 if resp.Close || rc.req.Close || resp.StatusCode <= 199 || bodyWritable { alive = false } //把response写入通道,在步骤6会读取这个通道 select { case rc.ch <- responseAndError{res: resp}: case <-rc.callerGone: return } //循环结束的一些情况 select { case bodyEOF := <-waitForBodyRead: //读完body也会自动结束 case <-rc.req.Cancel: case <-rc.req.Context().Done(): case <-pc.closech: alive = false pc.t.CancelRequest(rc.req) } }
5.4.1 pc.readResponse Get response
func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTrace) (resp *Response, err error) { for{ resp, err = ReadResponse(pc.br, rc.req) //获取response }}
5.4.2 ReadResponse Read response
func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) { tp := textproto.NewReader(r) //可以处理HTTP, NNTP, SMTP协议的内容,方便读取 resp := &Response{ Request: req, } line, err := tp.ReadLine()//读取第一行,获取协议,状态码 resp.Proto = line[:i] resp.Status = strings.TrimLeft(line[i+1:], " ") mimeHeader, err := tp.ReadMIMEHeader()//读取header头 resp.Header = Header(mimeHeader)}
5.5 Writing coroutine
func (pc *persistConn) writeLoop() { for { select { case wr := <-pc.writech: startBytesWritten := pc.nwrite err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh)) }}
6. Use the connection object *persistConn to get the response
func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) { var continueCh chan struct{} resc := make(chan responseAndError) //response通道 pc.writech <- writeRequest{req, writeErrCh, continueCh}//written by roundTrip; read by writeLoop pc.reqch <- requestAndChan{ //written by roundTrip; read by readLoop req: req.Request, ch: resc, addedGzip: requestedGzip, continueCh: continueCh, callerGone: gone, } for { //监听这些通道 testHookWaitResLoop() select { case err := <-writeErrCh: case <-pc.closech: case re := <-resc: //监听 response通道,返回response return re.res, nil } }}
The above is the detailed content of Parsing Go's http client. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Reading and writing files safely in Go is crucial. Guidelines include: Checking file permissions Closing files using defer Validating file paths Using context timeouts Following these guidelines ensures the security of your data and the robustness of your application.

How to configure connection pooling for Go database connections? Use the DB type in the database/sql package to create a database connection; set MaxOpenConns to control the maximum number of concurrent connections; set MaxIdleConns to set the maximum number of idle connections; set ConnMaxLifetime to control the maximum life cycle of the connection.

JSON data can be saved into a MySQL database by using the gjson library or the json.Unmarshal function. The gjson library provides convenience methods to parse JSON fields, and the json.Unmarshal function requires a target type pointer to unmarshal JSON data. Both methods require preparing SQL statements and performing insert operations to persist the data into the database.

The difference between the GoLang framework and the Go framework is reflected in the internal architecture and external features. The GoLang framework is based on the Go standard library and extends its functionality, while the Go framework consists of independent libraries to achieve specific purposes. The GoLang framework is more flexible and the Go framework is easier to use. The GoLang framework has a slight advantage in performance, and the Go framework is more scalable. Case: gin-gonic (Go framework) is used to build REST API, while Echo (GoLang framework) is used to build web applications.

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

Go framework development FAQ: Framework selection: Depends on application requirements and developer preferences, such as Gin (API), Echo (extensible), Beego (ORM), Iris (performance). Installation and use: Use the gomod command to install, import the framework and use it. Database interaction: Use ORM libraries, such as gorm, to establish database connections and operations. Authentication and authorization: Use session management and authentication middleware such as gin-contrib/sessions. Practical case: Use the Gin framework to build a simple blog API that provides POST, GET and other functions.

Which libraries in Go are developed by large companies or well-known open source projects? When programming in Go, developers often encounter some common needs, ...

Go language performs well in building efficient and scalable systems. Its advantages include: 1. High performance: compiled into machine code, fast running speed; 2. Concurrent programming: simplify multitasking through goroutines and channels; 3. Simplicity: concise syntax, reducing learning and maintenance costs; 4. Cross-platform: supports cross-platform compilation, easy deployment.
