這篇文章給大家分享的是有關(guān)Go中http client的示例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。
創(chuàng)新互聯(lián)建站專業(yè)IDC數(shù)據(jù)服務(wù)器托管提供商,專業(yè)提供成都服務(wù)器托管,服務(wù)器租用,綿陽服務(wù)器托管,綿陽服務(wù)器托管,成都多線服務(wù)器托管等服務(wù)器托管服務(wù)。
go是golang的簡稱,golang 是Google開發(fā)的一種靜態(tài)強(qiáng)類型、編譯型、并發(fā)型,并具有垃圾回收功能的編程語言,其語法與 C語言相近,但并不包括如枚舉、異常處理、繼承、泛型、斷言、虛函數(shù)等功能。
go封裝了http客戶端,請(qǐng)求遠(yuǎn)程數(shù)據(jù)非常方便,看些源碼底層如何實(shí)現(xiàn)。
resp, err := http.Get("https://baidu.com") if err != nil { fmt.Printf("發(fā)起請(qǐng)求失?。?v", err) return }defer resp.Body.Close() io.Copy(os.Stdout, resp.Body)
請(qǐng)求的大致流程
func (c *Client) do(req *Request) (retres *Response, reterr error)
func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error)resp, didTimeout, err = send(req, c.transport(), deadline)//默認(rèn)傳DefaultTransport
func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) { resp, err = rt.RoundTrip(req) }
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) //使用連接池技術(shù),獲取連接對(duì)象*persistConn, resp, err = pconn.roundTrip(treq) //使用連接對(duì)象獲取response}
func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) { w := &wantConn{ //構(gòu)建連接對(duì)象 cm: cm, key: cm.key(), ctx: ctx, ready: make(chan struct{}, 1), beforeDial: testHookPrePendingDial, afterDial: testHookPostPendingDial, } if delivered := t.queueForIdleConn(w); delivered {//從連接池獲取符合的連接對(duì)象,有就返回 pc := w.pc return pc, nil } t.queueForDial(w)//發(fā)起連接 select { case <-w.ready: //連接準(zhǔn)備好,就返回連接對(duì)象 return w.pc, w.err}
func (t *Transport) queueForDial(w *wantConn) { go t.dialConnFor(w)}
func (t *Transport) dialConnFor(w *wantConn) { pc, err := t.dialConn(w.ctx, w.cm) //發(fā)起撥號(hào),返回連接對(duì)象 delivered := w.tryDeliver(pc, err)}
func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) { pconn = &persistConn{ //構(gòu)建連接對(duì)象 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對(duì)象 pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())//可以從conn讀 pconn.bw = bufio.NewWriterSize(persistConnWriter{pconn}, t.writeBufferSize())//寫到conn go pconn.readLoop()//開啟讀協(xié)程 go pconn.writeLoop()//開啟寫協(xié)程 return pconn, nil}
func (pc *persistConn) readLoop() { alive := true for alive { rc := <-pc.reqch //讀取request,寫入的地方在步驟6 resp, err = pc.readResponse(rc, trace) //返回response //response的body是否可寫,服務(wù)器code101才可寫,所以正常這個(gè)是false bodyWritable := resp.bodyIsWritable() //response.Close設(shè)置循環(huán)結(jié)束,退出協(xié)程 if resp.Close || rc.req.Close || resp.StatusCode <= 199 || bodyWritable { alive = false } //把response寫入通道,在步驟6會(huì)讀取這個(gè)通道 select { case rc.ch <- responseAndError{res: resp}: case <-rc.callerGone: return } //循環(huán)結(jié)束的一些情況 select { case bodyEOF := <-waitForBodyRead: //讀完body也會(huì)自動(dòng)結(jié)束 case <-rc.req.Cancel: case <-rc.req.Context().Done(): case <-pc.closech: alive = false pc.t.CancelRequest(rc.req) } }
func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTrace) (resp *Response, err error) { for{ resp, err = ReadResponse(pc.br, rc.req) //獲取response }}
func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) { tp := textproto.NewReader(r) //可以處理HTTP, NNTP, SMTP協(xié)議的內(nèi)容,方便讀取 resp := &Response{ Request: req, } line, err := tp.ReadLine()//讀取第一行,獲取協(xié)議,狀態(tài)碼 resp.Proto = line[:i] resp.Status = strings.TrimLeft(line[i+1:], " ") mimeHeader, err := tp.ReadMIMEHeader()//讀取header頭 resp.Header = Header(mimeHeader)}
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)) }}
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 { //監(jiān)聽這些通道 testHookWaitResLoop() select { case err := <-writeErrCh: case <-pc.closech: case re := <-resc: //監(jiān)聽 response通道,返回response return re.res, nil } }}
感謝各位的閱讀!關(guān)于“Go中http client的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!