golang中fasthttp的funcGet为什么有“dst”参数



我找到了fasthttp godoc作为同事:

func Get
func Get(dst []byte, url string) (statusCode int, body []byte, err error)
Get appends url contents to dst and returns it as body.
The function follows redirects. Use Do* for manually handling redirects.
New body buffer is allocated if dst is nil.

但是,当我运行同事代码时

package main
import (
    "fmt"
    fh "github.com/valyala/fasthttp"
)
func main() {
    url := "https://www.okcoin.cn/api/v1/ticker.do?symbol=btc_cny"
    dst := []byte("ok100")
    _, body, err := fh.Get(dst, url)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("body:", string(body))
    fmt.Println("dst:", string(dst))
}

body没有"ok100",dst仍然是"ok100"。为什么?

查看fasthttp的client.go func clientGetURLeadlineFreeConn中使用的代码(第672行),您可以看到,如果出现超时,dst的内容将在第712行复制到body。因此,根据我在代码中读到的内容(并使用您的代码使用Delve进行调试),我发现dst在这种用法中不会更新。它似乎可以用于在超时的情况下向主体提供默认内容——可能值得直接向fasthttp的作者询问更多细节。

func clientGetURLDeadlineFreeConn(dst []byte, url string, deadline time.Time, c clientDoer) (statusCode int, body []byte, err error) {
timeout := -time.Since(deadline)
if timeout <= 0 {
    return 0, dst, ErrTimeout
}
var ch chan clientURLResponse
chv := clientURLResponseChPool.Get()
if chv == nil {
    chv = make(chan clientURLResponse, 1)
}
ch = chv.(chan clientURLResponse)
req := AcquireRequest()
// Note that the request continues execution on ErrTimeout until
// client-specific ReadTimeout exceeds. This helps limiting load
// on slow hosts by MaxConns* concurrent requests.
//
// Without this 'hack' the load on slow host could exceed MaxConns*
// concurrent requests, since timed out requests on client side
// usually continue execution on the host.
go func() {
    statusCodeCopy, bodyCopy, errCopy := doRequestFollowRedirects(req, dst, url, c)
    ch <- clientURLResponse{
        statusCode: statusCodeCopy,
        body:       bodyCopy,
        err:        errCopy,
    }
}()
tc := acquireTimer(timeout)
select {
case resp := <-ch:
    ReleaseRequest(req)
    clientURLResponseChPool.Put(chv)
    statusCode = resp.statusCode
    body = resp.body
    err = resp.err
case <-tc.C:
    body = dst
    err = ErrTimeout
}
releaseTimer(tc)
return statusCode, body, err

}

在client.go func doRequestFollowRedirects(第743行)中,它用于第748行:bodyBuf.B=dst

func doRequestFollowRedirects(req *Request, dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) {
resp := AcquireResponse()
bodyBuf := resp.bodyBuffer()
resp.keepBodyBuffer = true
oldBody := bodyBuf.B
bodyBuf.B = dst
redirectsCount := 0
for {
    req.parsedURI = false
    req.Header.host = req.Header.host[:0]
    req.SetRequestURI(url)
    if err = c.Do(req, resp); err != nil {
        break
    }
    statusCode = resp.Header.StatusCode()
    if statusCode != StatusMovedPermanently && statusCode != StatusFound && statusCode != StatusSeeOther {
        break
    }
    redirectsCount++
    if redirectsCount > maxRedirectsCount {
        err = errTooManyRedirects
        break
    }
    location := resp.Header.peek(strLocation)
    if len(location) == 0 {
        err = errMissingLocation
        break
    }
    url = getRedirectURL(url, location)
}
body = bodyBuf.B
bodyBuf.B = oldBody
resp.keepBodyBuffer = false
ReleaseResponse(resp)
return statusCode, body, err

}

最新更新