代码拉取完成,页面将自动刷新
/*
* @Author: lixu lixu@puchigames.com
* @Date: 2025-06-16 10:40:44
* @LastEditors: lixu lixu@puchigames.com
* @LastEditTime: 2025-06-17 10:44:20
* @FilePath: /go-helper/utils/http.go
* @Description: HTTP相关工具函数,包含请求、响应、Cookie、Session等处理功能
*/
package ixUtils
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net"
"net/http"
"net/http/cookiejar"
"net/url"
"os"
"path/filepath"
"strings"
"time"
)
// ---------------------HTTP请求配置---------------------------------------
// HttpConfig HTTP请求配置
type HttpConfig struct {
Timeout time.Duration // 超时时间
RetryTimes int // 重试次数
RetryDelay time.Duration // 重试延迟
Headers map[string]string // 请求头
Cookies []*http.Cookie // Cookie
Proxy string // 代理地址
Insecure bool // 是否跳过SSL验证
UserAgent string // User-Agent
BasicAuth *BasicAuth // Basic认证
MaxRedirect int // 最大重定向次数
}
// BasicAuth Basic认证信息
type BasicAuth struct {
Username string
Password string
}
// DefaultHttpConfig 默认HTTP配置
var DefaultHttpConfig = HttpConfig{
Timeout: 30 * time.Second,
RetryTimes: 3,
RetryDelay: time.Second,
Headers: map[string]string{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
},
MaxRedirect: 5,
}
// ---------------------HTTP客户端---------------------------------------
// NewHttpClient 创建HTTP客户端
func NewHttpClient(config *HttpConfig) (*http.Client, error) {
if config == nil {
config = &DefaultHttpConfig
}
// 创建Cookie Jar
jar, err := cookiejar.New(nil)
if err != nil {
return nil, err
}
// 创建Transport
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: config.Timeout,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
// 配置代理
if config.Proxy != "" {
proxyURL, err := url.Parse(config.Proxy)
if err != nil {
return nil, err
}
transport.Proxy = http.ProxyURL(proxyURL)
}
// 配置SSL验证
if config.Insecure {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
// 创建客户端
client := &http.Client{
Transport: transport,
Jar: jar,
Timeout: config.Timeout,
}
// 配置重定向
if config.MaxRedirect > 0 {
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
if len(via) >= config.MaxRedirect {
return fmt.Errorf("stopped after %d redirects", config.MaxRedirect)
}
return nil
}
}
return client, nil
}
// ---------------------HTTP请求---------------------------------------
// HttpRequest HTTP请求
func HttpRequest(method, url string, body interface{}, config *HttpConfig) (*http.Response, error) {
if method == "" {
return nil, fmt.Errorf("method cannot be empty")
}
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
// 使用默认配置
if config == nil {
config = &DefaultHttpConfig
}
client, err := NewHttpClient(config)
if err != nil {
return nil, err
}
// 准备请求体
var reqBody io.Reader
if body != nil {
switch v := body.(type) {
case string:
reqBody = strings.NewReader(v)
case []byte:
reqBody = bytes.NewReader(v)
case map[string]string:
values := make(map[string][]string)
for k, v := range v {
values[k] = []string{v}
}
reqBody = strings.NewReader(buildQueryString(values))
default:
jsonData, err := json.Marshal(v)
if err != nil {
return nil, err
}
reqBody = bytes.NewReader(jsonData)
}
}
// 创建请求
req, err := http.NewRequest(method, url, reqBody)
if err != nil {
return nil, err
}
// 设置请求头
for key, value := range config.Headers {
req.Header.Set(key, value)
}
// 设置Cookie
for _, cookie := range config.Cookies {
req.AddCookie(cookie)
}
// 设置Basic认证
if config.BasicAuth != nil {
req.SetBasicAuth(config.BasicAuth.Username, config.BasicAuth.Password)
}
// 发送请求(带重试)
var resp *http.Response
var lastErr error
for i := 0; i <= config.RetryTimes; i++ {
resp, lastErr = client.Do(req)
if lastErr == nil {
break
}
if i < config.RetryTimes {
time.Sleep(config.RetryDelay)
}
}
return resp, lastErr
}
// buildQueryString 构建查询字符串
func buildQueryString(params map[string][]string) string {
if len(params) == 0 {
return ""
}
var buf strings.Builder
for k, v := range params {
for _, val := range v {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(url.QueryEscape(k))
buf.WriteByte('=')
buf.WriteString(url.QueryEscape(val))
}
}
return buf.String()
}
// ---------------------便捷请求方法---------------------------------------
// Get 发送GET请求
func Get(url string, config ...*HttpConfig) (*http.Response, error) {
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
var cfg *HttpConfig
if len(config) > 0 {
cfg = config[0]
}
return HttpRequest(http.MethodGet, url, nil, cfg)
}
// Post 发送POST请求
func Post(url string, args ...interface{}) (*http.Response, error) {
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
var body interface{}
var cfg *HttpConfig
for _, arg := range args {
switch v := arg.(type) {
case *HttpConfig:
cfg = v
default:
body = v
}
}
return HttpRequest(http.MethodPost, url, body, cfg)
}
// Put 发送PUT请求
func Put(url string, args ...interface{}) (*http.Response, error) {
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
var body interface{}
var cfg *HttpConfig
for _, arg := range args {
switch v := arg.(type) {
case *HttpConfig:
cfg = v
default:
body = v
}
}
return HttpRequest(http.MethodPut, url, body, cfg)
}
// Delete 发送DELETE请求
func Delete(url string, config ...*HttpConfig) (*http.Response, error) {
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
var cfg *HttpConfig
if len(config) > 0 {
cfg = config[0]
}
return HttpRequest(http.MethodDelete, url, nil, cfg)
}
// Patch 发送PATCH请求
func Patch(url string, args ...interface{}) (*http.Response, error) {
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
var body interface{}
var cfg *HttpConfig
for _, arg := range args {
switch v := arg.(type) {
case *HttpConfig:
cfg = v
default:
body = v
}
}
return HttpRequest(http.MethodPatch, url, body, cfg)
}
// ---------------------响应处理---------------------------------------
// ReadResponse 读取响应内容
func ReadResponse(resp *http.Response) ([]byte, error) {
if resp == nil {
return nil, fmt.Errorf("response is nil")
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
// ReadResponseString 读取响应内容为字符串
func ReadResponseString(resp *http.Response) (string, error) {
body, err := ReadResponse(resp)
if err != nil {
return "", err
}
return string(body), nil
}
// ReadResponseJson 读取响应内容为JSON
func ReadResponseJson(resp *http.Response, v interface{}) error {
if v == nil {
return fmt.Errorf("target interface is nil")
}
body, err := ReadResponse(resp)
if err != nil {
return err
}
return json.Unmarshal(body, v)
}
// ---------------------文件上传---------------------------------------
// UploadFile 上传文件
func UploadFile(url string, fieldName, filePath string, extraFields map[string]string, config *HttpConfig) (*http.Response, error) {
if url == "" {
return nil, fmt.Errorf("url cannot be empty")
}
if fieldName == "" {
return nil, fmt.Errorf("field name cannot be empty")
}
if filePath == "" {
return nil, fmt.Errorf("file path cannot be empty")
}
// 检查文件是否存在
if !FileExists(filePath) {
return nil, fmt.Errorf("file does not exist: %s", filePath)
}
// 创建multipart writer
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// 添加文件
file, err := writer.CreateFormFile(fieldName, filepath.Base(filePath))
if err != nil {
return nil, err
}
// 读取文件内容
fileContent, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
// 写入文件内容
if _, err := file.Write(fileContent); err != nil {
return nil, err
}
// 添加额外字段
for key, value := range extraFields {
if err := writer.WriteField(key, value); err != nil {
return nil, err
}
}
// 关闭writer
if err := writer.Close(); err != nil {
return nil, err
}
// 设置Content-Type
if config == nil {
config = &DefaultHttpConfig
}
if config.Headers == nil {
config.Headers = make(map[string]string)
}
config.Headers["Content-Type"] = writer.FormDataContentType()
// 发送请求
return Post(url, body, config)
}
// ---------------------Cookie处理---------------------------------------
// GetCookies 获取响应中的Cookie
func GetCookies(resp *http.Response) []*http.Cookie {
if resp == nil {
return nil
}
return resp.Cookies()
}
// GetCookie 获取指定名称的Cookie
func GetCookie(resp *http.Response, name string) *http.Cookie {
if resp == nil {
return nil
}
if name == "" {
return nil
}
for _, cookie := range resp.Cookies() {
if cookie.Name == name {
return cookie
}
}
return nil
}
// ---------------------URL处理---------------------------------------
// BuildUrl 构建URL
func BuildUrl(baseUrl string, params map[string]string) string {
if baseUrl == "" {
return ""
}
if len(params) == 0 {
return baseUrl
}
values := url.Values{}
for key, value := range params {
values.Set(key, value)
}
if strings.Contains(baseUrl, "?") {
return baseUrl + "&" + values.Encode()
}
return baseUrl + "?" + values.Encode()
}
// ParseUrl 解析URL
func ParseUrl(urlStr string) (*url.URL, error) {
if urlStr == "" {
return nil, fmt.Errorf("url string cannot be empty")
}
return url.Parse(urlStr)
}
// ---------------------错误处理---------------------------------------
// IsTimeoutError 判断是否为超时错误
func IsTimeoutError(err error) bool {
if err == nil {
return false
}
if netErr, ok := err.(net.Error); ok {
return netErr.Timeout()
}
return false
}
// IsConnectionError 判断是否为连接错误
func IsConnectionError(err error) bool {
if err == nil {
return false
}
if netErr, ok := err.(net.Error); ok {
return !netErr.Timeout()
}
return false
}
/*
使用示例:
// 1. 最简单的GET请求
resp, err := Get("https://api.example.com")
if err != nil {
// 处理错误
}
body, err := ReadResponseString(resp)
// 2. 带配置的GET请求
config := &HttpConfig{
Timeout: 5 * time.Second,
Headers: map[string]string{
"Authorization": "Bearer token123",
},
}
resp, err := Get("https://api.example.com", config)
// 3. 带表单数据的POST请求
data := map[string]string{
"name": "test",
"age": "18",
}
resp, err := Post("https://api.example.com", data)
// 4. 带JSON数据的POST请求
jsonData := map[string]interface{}{
"name": "test",
"age": 18,
}
resp, err := Post("https://api.example.com", jsonData)
// 5. 带数据和配置的POST请求
resp, err := Post("https://api.example.com", jsonData, config)
// 6. 文件上传
extraFields := map[string]string{
"description": "test file",
}
resp, err := UploadFile("https://api.example.com/upload", "file", "test.txt", extraFields, config)
// 7. 处理响应
// 读取字符串响应
body, err := ReadResponseString(resp)
// 读取JSON响应
var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
err = ReadResponseJson(resp, &result)
// 8. 获取Cookie
cookies := GetCookies(resp)
sessionCookie := GetCookie(resp, "session")
// 9. 构建URL
url := BuildUrl("https://api.example.com", map[string]string{
"page": "1",
"size": "10",
})
// 10. 错误处理
if IsTimeoutError(err) {
// 处理超时错误
}
*/
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。