package starnet import ( "bytes" "encoding/json" "io" "net/http" "sync" ) // Response HTTP 响应 type Response struct { *http.Response request *Request httpClient *http.Client body *Body } // Body 响应体 type Body struct { raw io.ReadCloser data []byte consumed bool mu sync.Mutex } // Request 获取原始请求 func (r *Response) Request() *Request { return r.request } // Body 获取响应体 func (r *Response) Body() *Body { return r.body } // Close 关闭响应体 func (r *Response) Close() error { if r.body != nil && r.body.raw != nil { return r.body.raw.Close() } return nil } // CloseWithClient 关闭响应体并关闭空闲连接 func (r *Response) CloseWithClient() error { if r.httpClient != nil { r.httpClient.CloseIdleConnections() } return r.Close() } // readAll 读取所有数据 func (b *Body) readAll() error { b.mu.Lock() defer b.mu.Unlock() if b.consumed { return nil } if b.raw == nil { b.consumed = true return nil } data, err := io.ReadAll(b.raw) if err != nil { return wrapError(err, "read response body") } b.data = data b.consumed = true b.raw.Close() return nil } // Bytes 获取响应体字节 func (b *Body) Bytes() ([]byte, error) { if err := b.readAll(); err != nil { return nil, err } return b.data, nil } // String 获取响应体字符串 func (b *Body) String() (string, error) { data, err := b.Bytes() if err != nil { return "", err } return string(data), nil } // JSON 解析 JSON 响应 func (b *Body) JSON(v interface{}) error { data, err := b.Bytes() if err != nil { return err } return json.Unmarshal(data, v) } // Reader 获取 Reader(只能调用一次) func (b *Body) Reader() (io.ReadCloser, error) { b.mu.Lock() defer b.mu.Unlock() if b.consumed { if b.data != nil { // 已读取,返回缓存数据的 Reader return io.NopCloser(bytes.NewReader(b.data)), nil } return nil, ErrBodyAlreadyConsumed } b.consumed = true return b.raw, nil } // IsConsumed 检查是否已消费 func (b *Body) IsConsumed() bool { b.mu.Lock() defer b.mu.Unlock() return b.consumed } // Close 关闭 Body func (b *Body) Close() error { b.mu.Lock() defer b.mu.Unlock() if b.raw != nil { return b.raw.Close() } return nil } // MustBytes 获取响应体字节(忽略错误,失败返回 nil) func (b *Body) MustBytes() []byte { data, err := b.Bytes() if err != nil { return nil } return data } // MustString 获取响应体字符串(忽略错误,失败返回空串) func (b *Body) MustString() string { s, err := b.String() if err != nil { return "" } return s } // Unmarshal 解析 JSON 响应(兼容旧 API) func (b *Body) Unmarshal(v interface{}) error { return b.JSON(v) }