>  기사  >  백엔드 개발  >  Go의 http 클라이언트 구문 분석

Go의 http 클라이언트 구문 분석

藏色散人
藏色散人앞으로
2021-05-10 11:37:124876검색

다음 튜토리얼 칼럼인 golang에서는 Go의 http 클라이언트를 소개하겠습니다. 필요한 친구들에게 도움이 되길 바랍니다!

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. 요청 조건에 따라 요청 개체를 구성합니다

2. 모든 클라이언트 요청은 client.do()

func (c *Client) do(req *Request) (retres *Response, reterr error)

2.1 요청 요청에 의해 처리됩니다. 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}
S 5.1 Transport.queueFordial은 DialConnFor

R
func (t *Transport) queueForDial(w *wantConn) {
    go t.dialConnFor(w)}
E

5.3 다이얼을 시작하기 위해
func (t *Transport) dialConnFor(w *wantConn) {
    pc, err := t.dialConn(w.ctx, w.cm) //发起拨号,返回连接对象
    delivered := w.tryDeliver(pc, err)}
5.2 연결을 시작했습니다. 공개할 코루틴
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}
E
5.4.1 응답을 얻기 위한 PC.ReadResponse
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.2 ReadResponse
6. 연결 객체를 사용하여 *persistConn을 사용하세요.

위 내용은 Go의 http 클라이언트 구문 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제