golang http请求底层逻辑主要位于 net/http/transport.go 文件,roundTrip是发起http请求和处理http响应的主体方法。
roundTrip { // transport.go
testHookWaitResLoop() { // 此方法包含建立tcp连接的所有细节
=> resc := make(chan responseAndError) // 创建http响应通道,用来接收http响应
=> dialConn // 正式请求http
=> dial(ctx context.Context, network, addr string) (net.Conn, error)
=> transport.go @ conn, err := t.dial(ctx, "tcp", cm.addr()) // 进入tcp构建阶段
=> transport.go @ DialContext
=> net/dial.go @ dialParallel => dialSerial => dialSingle
=> net/tcpsock_posix.go @ dialTCP => doDialTCP
=> net/ipsock_posix.go @ internetSocket // 获得tcp连接创建后的fd,即file descriptor
=> net/sock_posix.go @ fd.dial(ctx, laddr, raddr, ctrlCtxFn) // 用fd来拨号
=> net/ipsock_posix.go @ newTCPConn() // 返回TcpConn对象
=> transport.go // 拨号完毕回到 transport
=> go pconn.readLoop() // 通过协程,用包含TcpConn对象的persistConn对象读取和处理http响应
=> resp, err = pc.readResponse(rc, trace) { // 读取 http response
resp, err = ReadResponse(pc.br, rc.req) // 通过bufio.Reader来逐行读取http响应
resCode := resp.StatusCode // http状态码
}
=> select {
case rc.ch <- responseAndError{err: err}: // 将最终响应内容发送给 responseAndError 通道
}
}
select {
case re := <-resc: // 从responseAndError通道正常接收http响应
return re.res, nil
case <-cancelChan: // 接收Request的cancel通道
canceled = pc.t.cancelRequest(req.cancelKey, errRequestCanceled)
cancelChan = nil
case <-ctxDoneChan: // 接收context的done通道
canceled = pc.t.cancelRequest(req.cancelKey, req.Context().Err())
cancelChan = nil
ctxDoneChan = nil
}
}
}