91 lines
2.3 KiB
Go

package httpclient
import (
"bufio"
"bytes"
"io"
"net/http"
"strings"
"time"
)
// NetHTTPClient 使用 net/http 实现 HTTPClient 接口
type NetHTTPClient struct {
client *http.Client
// 可根据需要添加对象池
}
// NewNetHTTPClient 返回一个初始化的 NetHTTPClient
func NewNetHTTPClient() *NetHTTPClient {
return &NetHTTPClient{client: &http.Client{}}
}
// Do 发送非流式请求
func (c *NetHTTPClient) Do(req *Request) (*Response, error) {
r, err := http.NewRequest(req.Method, req.URL, bytes.NewReader(req.Body))
if err != nil {
return nil, err
}
for k, v := range req.Headers {
r.Header.Set(k, v)
}
resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
headers := make(map[string]string)
for k, v := range resp.Header {
headers[k] = v[0]
}
return &Response{StatusCode: resp.StatusCode, Body: body, Headers: headers}, nil
}
// Stream 发送流式请求,逐块通过 callback 回调 SSE 数据
func (c *NetHTTPClient) Stream(req *Request, callback func(chunk SSEChunk) error) error {
r, err := http.NewRequest(req.Method, req.URL, bytes.NewReader(req.Body))
if err != nil {
return err
}
for k, v := range req.Headers {
r.Header.Set(k, v)
}
resp, err := c.client.Do(r)
if err != nil {
return err
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
text := scanner.Text()
if text == "" {
continue
}
const prefix = "data: "
if strings.HasPrefix(text, prefix) {
payload := text[len(prefix):]
isDone := payload == "[DONE]"
var dataBytes []byte
if !isDone {
dataBytes = []byte(payload)
}
chunk := SSEChunk{
Data: dataBytes,
Timestamp: time.Now().UnixNano(),
IsDone: isDone,
}
if err := callback(chunk); err != nil {
return err
}
}
}
if err := scanner.Err(); err != nil {
return err
}
return nil
}