58 lines
1.7 KiB
Go

package httpclient
import (
"sync"
"github.com/valyala/fasthttp"
)
// FastHTTPClient 使用 fasthttp 实现 HTTPClient 接口
type FastHTTPClient struct {
client *fasthttp.Client
reqPool *sync.Pool
respPool *sync.Pool
}
// NewFastHTTPClient 返回一个初始化的 FastHTTPClient
func NewFastHTTPClient() *FastHTTPClient {
return &FastHTTPClient{
client: &fasthttp.Client{},
reqPool: &sync.Pool{New: func() interface{} { return new(fasthttp.Request) }},
respPool: &sync.Pool{New: func() interface{} { return new(fasthttp.Response) }},
}
}
// Do 发送非流式请求
func (c *FastHTTPClient) Do(req *Request) (*Response, error) {
fr := c.reqPool.Get().(*fasthttp.Request)
defer c.reqPool.Put(fr)
fr.Header.SetMethod(req.Method)
fr.SetRequestURI(req.URL)
if len(req.Body) > 0 {
fr.SetBody(req.Body)
}
for k, v := range req.Headers {
fr.Header.Set(k, v)
}
fresp := c.respPool.Get().(*fasthttp.Response)
defer c.respPool.Put(fresp)
if err := c.client.Do(fr, fresp); err != nil {
return nil, err
}
resp := &Response{
StatusCode: fresp.StatusCode(),
Body: append([]byte(nil), fresp.Body()...),
Headers: make(map[string]string),
}
fresp.Header.VisitAll(func(k, v []byte) {
resp.Headers[string(k)] = string(v)
})
return resp, nil
}
// Stream 发送流式请求,逐块通过 callback 回调 SSE 数据
// 目前使用 net/http 实现 SSE 解析,后续可优化为 fasthttp 原生实现
func (c *FastHTTPClient) Stream(req *Request, callback func(chunk SSEChunk) error) error {
return NewNetHTTPClient().Stream(req, callback)
}