91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go中http client的示例分析

發布時間:2021-05-10 14:03:08 來源:億速云 閱讀:1314 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關Go中http client的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

什么是go

go是golang的簡稱,golang 是Google開發的一種靜態強類型、編譯型、并發型,并具有垃圾回收功能的編程語言,其語法與 C語言相近,但并不包括如枚舉、異常處理、繼承、泛型、斷言、虛函數等功能。

      

http client

go封裝了http客戶端,請求遠程數據非常方便,看些源碼底層如何實現。

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.根據請求條件,構建request對象

2.所有的client請求,都會經過client.do()處理

func (c *Client) do(req *Request) (retres *Response, reterr error)
2.1 request請求使用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函數

func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
    resp, err = rt.RoundTrip(req) }

4.DefaultTransport的RoundTrip方法,實際就是Transport的RoundTrip方法

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.使用連接池技術,獲取連接對象*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發起連接
func (t *Transport) queueForDial(w *wantConn) {
    go t.dialConnFor(w)}
5.2 發起撥號dialConnFor
func (t *Transport) dialConnFor(w *wantConn) {
    pc, err := t.dialConn(w.ctx, w.cm) //發起撥號,返回連接對象
    delivered := w.tryDeliver(pc, err)}
5.3 發起撥號
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讀協程,雖然是for循環,但是一次性就把請求的response讀完了,如果沒有關閉,就會造成協程泄露了
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 獲取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讀取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 寫協程
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.使用連接對象*persistConn獲取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
        }
    }}

感謝各位的閱讀!關于“Go中http client的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

邹城市| 会宁县| 安岳县| 东乡族自治县| 南宁市| 历史| 介休市| 金平| 曲靖市| 上饶县| 开化县| 林州市| 徐汇区| 兴安盟| 庄浪县| 台州市| 滦平县| 木里| 徐州市| 威信县| 海兴县| 鄱阳县| 德兴市| 南召县| 忻城县| 冷水江市| 浪卡子县| 丰台区| 虎林市| 西峡县| 大田县| 永安市| 杭州市| 延边| 神农架林区| 清新县| 安吉县| 香河县| 漾濞| 长汀县| 景宁|