Surf:为 Go 语言打造的现代、强大且易用的 HTTP 客户端

Surf HTTP Client for Go

在当今的软件开发中,HTTP 客户端是与外部 API 和服务交互不可或缺的组件。无论是构建微服务架构、数据采集系统还是简单的 API 调用,一个强大且灵活的 HTTP 客户端都能显著提升开发效率和应用程序性能。

今天,我们将深入探讨 Surf,一个为 Go 语言设计的现代化 HTTP 客户端库。Surf 不仅提供了标准库的功能,还加入了许多高级特性,让 HTTP 请求处理变得简单而高效。

什么是 Surf?

Surf 是一个功能丰富的 HTTP 客户端库,专为 Go 语言开发者设计。它建立在标准 net/http 包的基础上,提供了更加直观和强大的 API,让开发者能够轻松处理复杂的 HTTP 交互场景。

这个库的独特之处在于它支持浏览器模拟、高级 TLS 指纹定制、HTTP/3 协议支持,以及完整的中间件系统。无论你是需要简单的 API 调用,还是复杂的网页采集任务,Surf 都能提供合适的工具和功能。

核心特性概览

浏览器模拟功能

Surf 能够精确模拟现代浏览器的行为,包括 Chrome 和 Firefox 的最新版本。这意味着你的 HTTP 请求会看起来像是来自真实的浏览器,包括正确的头部顺序、TLS 指纹和协议支持。

高级 TLS 和安全特性

支持 JA3/JA4 指纹定制,允许你精确控制 TLS 握手过程中的各种参数。这对于需要绕过某些安全检测的场景特别有用。

HTTP/3 和 QUIC 支持

Surf 提供了完整的 HTTP/3 over QUIC 支持,包括浏览器特定的 QUIC 指纹模拟。这让你能够利用最新的网络协议优势。

性能与可靠性

内置连接池、自动重试机制、响应缓存和流式处理等功能,确保你的应用程序既快速又可靠。

开发者体验

提供流畅的 API 设计、完整的中间件系统和标准库兼容性,让集成和使用变得异常简单。

开始使用 Surf

安装要求

要使用 Surf,你需要安装 Go 1.24 或更高版本。安装过程非常简单,只需要执行以下命令:

go get -u github.com/enetx/surf

这个命令会下载 Surf 库及其所有依赖项。

第一个简单的请求

让我们从一个基本的 GET 请求开始,了解 Surf 的基本用法:

package main

import (
    "fmt"
    "log"
    "github.com/enetx/surf"
)

func main() {
    resp := surf.NewClient().Get("https://api.github.com/users/github").Do()
    if resp.IsErr() {
        log.Fatal(resp.Err())
    }

    fmt.Println(resp.Ok().Body.String())
}

这段代码创建了一个新的 HTTP 客户端,向 GitHub API 发送 GET 请求,并打印响应内容。Surf 使用了 Result 类型来处理错误,这让错误处理变得更加清晰和安全。

处理 JSON 响应

在现代 Web 开发中,JSON 是最常见的数据交换格式。Surf 让 JSON 处理变得非常简单:

type User struct {
    Name     string `json:"name"`
    Company  string `json:"company"`
    Location string `json:"location"`
}

resp := surf.NewClient().Get("https://api.github.com/users/github").Do()
if resp.IsOk() {
    var user User
    resp.Ok().Body.JSON(&user)
    fmt.Printf("User: %+v\n", user)
}

浏览器模拟实战

为什么需要浏览器模拟?

在许多场景下,简单的 HTTP 请求不足以完成任务。某些网站会检测请求的指纹特征,如果发现不是来自真实浏览器的请求,可能会拒绝服务或返回不同的内容。这就是浏览器模拟发挥作用的地方。

Chrome 浏览器模拟

Surf 可以轻松模拟 Chrome 浏览器:

client := surf.NewClient().
    Builder().
    Impersonate().
    Chrome().        // 使用最新 Chrome 版本
    Build()

resp := client.Get("https://example.com").Do()

Firefox 浏览器模拟

同样地,你也可以模拟 Firefox 浏览器:

client := surf.NewClient().
    Builder().
    Impersonate().
    FireFox().       // 使用最新 Firefox 版本
    Build()

多平台支持

Surf 支持模拟多种操作系统平台,包括 Windows、macOS、Linux、Android 和 iOS:

// 模拟 iOS 上的 Chrome
client := surf.NewClient().
    Builder().
    Impersonate().
    IOS().
    Chrome().
    Build()

// 模拟 Android 上的 Chrome
client := surf.NewClient().
    Builder().
    Impersonate().
    Android().
    Chrome().
    Build()

随机化选择

你甚至可以让 Surf 随机选择操作系统平台,增加请求的多样性:

client := surf.NewClient().
    Builder().
    Impersonate().
    RandomOS().      // 随机选择操作系统
    FireFox().       // 使用 Firefox
    Build()

HTTP/3 和 QUIC 深入解析

什么是 HTTP/3?

HTTP/3 是 HTTP 协议的最新版本,它使用 QUIC 协议而不是 TCP 作为传输层协议。QUIC 基于 UDP,提供了更快的连接建立、改进的多路复用和更好的移动网络性能。

启用 HTTP/3 支持

Surf 让 HTTP/3 的使用变得非常简单:

// 自动检测浏览器类型并配置相应的 HTTP/3 设置
client := surf.NewClient().
    Builder().
    Impersonate().Chrome().
    HTTP3().        // 启用 HTTP/3
    Build()

resp := client.Get("https://cloudflare-quic.com/").Do()
if resp.IsOk() {
    fmt.Printf("使用的协议: %s\n", resp.Ok().Proto) // 输出: HTTP/3.0
}

手动配置 HTTP/3

如果你需要更精细的控制,可以手动配置 HTTP/3 参数:

// 使用 Chrome 的 QUIC 设置
client := surf.NewClient().
    Builder().
    HTTP3Settings().Chrome().Set().
    Build()

// 使用 Firefox 的 QUIC 设置
client := surf.NewClient().
    Builder().
    HTTP3Settings().Firefox().Set().
    Build()

完整的指纹模拟

结合 TLS 指纹和 QUIC 指纹,可以实现完整的浏览器指纹模拟:

// 结合 TLS 指纹和 HTTP/3 QUIC 指纹
client := surf.NewClient().
    Builder().
    JA().Chrome131().               // TLS 指纹 (JA3/JA4)
    HTTP3Settings().Chrome().Set().  // 完整的 QUIC 指纹
    Build()

代理支持与兼容性

HTTP/3 与各种代理配置良好兼容:

// 使用 SOCKS5 代理支持 HTTP/3
client := surf.NewClient().
    Builder().
    Proxy("socks5://127.0.0.1:1080"). // SOCKS5 UDP 代理支持 HTTP/3
    HTTP3Settings().Chrome().Set().   // 将通过 SOCKS5 使用 HTTP/3
    Build()

高级配置技巧

自定义 TLS 指纹

Surf 允许精细控制 TLS 指纹:

// 使用特定浏览器版本的指纹
client := surf.NewClient().
    Builder().
    JA().
    Chrome().     // 最新 Chrome 指纹
    Build()

// 可用的浏览器指纹包括:
// Chrome: Chrome(), Chrome58(), Chrome70(), Chrome83(), Chrome96(), Chrome100(), Chrome102(), Chrome106(), Chrome120(), Chrome131()
// Firefox: Firefox(), Firefox55(), Firefox63(), Firefox99(), Firefox102(), Firefox105(), Firefox120(), Firefox131()
// Edge: Edge(), Edge85(), Edge106()
// Safari: Safari()
// 移动端: IOS(), IOS11(), IOS12(), IOS13(), IOS14(), Android()

// 使用随机指纹增强隐匿性
client := surf.NewClient().
    Builder().
    JA().
    Randomized().    // 随机 TLS 指纹
    Build()

HTTP/2 配置

虽然 HTTP/3 是新技术,但 HTTP/2 仍然广泛使用。Surf 允许精细配置 HTTP/2 参数:

client := surf.NewClient().
    Builder().
    HTTP2Settings().
    HeaderTableSize(65536).
    EnablePush(0).
    InitialWindowSize(6291456).
    MaxHeaderListSize(262144).
    ConnectionFlow(15663105).
    Set().
    Build()

代理配置

Surf 支持多种代理类型和轮询机制:

// 单一代理
client := surf.NewClient().
    Builder().
    Proxy("http://proxy.example.com:8080").
    Build()

// 代理轮询
proxies := []string{
    "http://proxy1.example.com:8080",
    "http://proxy2.example.com:8080",
    "socks5://proxy3.example.com:1080",
}

client := surf.NewClient().
    Builder().
    Proxy(proxies).  // 从列表中随机选择代理
    Build()

中间件系统

什么是中间件?

中间件是一种强大的设计模式,允许你在请求处理流程的不同阶段插入自定义逻辑。Surf 提供了完整的中间件系统,支持请求、响应和客户端级别的中间件。

请求中间件

请求中间件在请求发送之前执行,适合用于添加头部、记录日志或修改请求参数:

client := surf.NewClient().
    Builder().
    With(func(req *surf.Request) error {
        req.AddHeaders("X-Custom-Header", "value")
        fmt.Printf("请求发送至: %s\n", req.GetRequest().URL)
        return nil
    }).
    Build()

响应中间件

响应中间件在收到响应后执行,适合用于检查状态码、记录响应时间或处理错误:

client := surf.NewClient().
    Builder().
    With(func(resp *surf.Response) error {
        fmt.Printf("响应状态码: %d\n", resp.StatusCode)
        fmt.Printf("响应时间: %v\n", resp.Time)
        return nil
    }).
    Build()

客户端中间件

客户端中间件在客户端级别执行,适合用于修改客户端配置或添加全局逻辑:

client := surf.NewClient().
    Builder().
    With(func(client *surf.Client) {
        // 修改客户端配置
        client.GetClient().Timeout = 30 * time.Second
    }).
    Build()

各种请求类型示例

POST 请求与 JSON 数据

user := map[string]string{
    "name": "张三",
    "email": "zhangsan@example.com",
}

resp := surf.NewClient().
    Post("https://api.example.com/users", user).
    Do()

表单数据提交

formData := map[string]string{
    "username": "zhangsan",
    "password": "secret",
}

resp := surf.NewClient().
    Post("https://example.com/login", formData).
    Do()

文件上传

// 单文件上传
resp := surf.NewClient().
    FileUpload(
        "https://api.example.com/upload",
        "file",                    // 字段名
        "/path/to/file.pdf",       // 文件路径
    ).Do()

// 带额外表单数据的文件上传
extraData := g.MapOrd[string, string]{
    "description": "重要文档",
    "category": "报告",
}

resp := surf.NewClient().
    FileUpload(
        "https://api.example.com/upload",
        "file",
        "/path/to/file.pdf",
        extraData,
    ).Do()

多部分表单提交

fields := g.NewMapOrd[g.String, g.String]()
fields.Set("field1", "value1")
fields.Set("field2", "value2")

resp := surf.NewClient().
    Multipart("https://api.example.com/form", fields).
    Do()

会话管理

持久化会话

Surf 支持自动的 cookie 管理,让会话保持变得简单:

client := surf.NewClient().
    Builder().
    Session().        // 启用 cookie 存储
    Build()

// 登录
client.Post("https://example.com/login", credentials).Do()

// 后续请求会自动包含会话 cookies
resp := client.Get("https://example.com/dashboard").Do()

手动 Cookie 管理

如果你需要更精细的控制,可以手动管理 cookies:

// 设置 cookies
cookies := []*http.Cookie{
    {Name: "session", Value: "abc123"},
    {Name: "preference", Value: "dark_mode"},
}

resp := surf.NewClient().
    Get("https://example.com").
    AddCookies(cookies...).
    Do()

// 从响应中获取 cookies
if resp.IsOk() {
    for _, cookie := range resp.Ok().Cookies {
        fmt.Printf("Cookie: %s = %s\n", cookie.Name, cookie.Value)
    }
}

响应处理技巧

状态码检查

正确处理 HTTP 状态码是构建健壮应用的关键:

resp := surf.NewClient().Get("https://api.example.com/data").Do()

if resp.IsOk() {
    switch {
    case resp.Ok().StatusCode.IsSuccess():
        fmt.Println("请求成功!")
    case resp.Ok().StatusCode.IsRedirect():
        fmt.Println("请求重定向至:", resp.Ok().Location())
    case resp.Ok().StatusCode.IsClientError():
        fmt.Println("客户端错误:", resp.Ok().StatusCode)
    case resp.Ok().StatusCode.IsServerError():
        fmt.Println("服务器错误:", resp.Ok().StatusCode)
    }
}

响应体处理

Surf 提供了多种方法来处理响应体:

resp := surf.NewClient().Get("https://example.com/data").Do()
if resp.IsOk() {
    body := resp.Ok().Body

    // 作为字符串获取
    content := body.String()

    // 作为字节切片获取
    data := body.Bytes()

    // 计算 MD5 哈希
    hash := body.MD5()

    // 转换为 UTF-8
    utf8Content := body.UTF8()

    // 检查内容
    if body.Contains("success") {
        fmt.Println("请求成功!")
    }

    // 保存到文件
    err := body.Dump("response.html")
}

流式处理大响应

对于大文件或流式数据,使用流式处理可以节省内存:

resp := surf.NewClient().Get("https://example.com/large-file").Do()
if resp.IsOk() {
    reader := resp.Ok().Body.Stream()

    scanner := bufio.NewScanner(reader)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}

服务器发送事件 (SSE)

Surf 支持服务器发送事件的处理:

resp := surf.NewClient().Get("https://example.com/events").Do()
if resp.IsOk() {
    resp.Ok().Body.SSE(func(event *sse.Event) bool {
        fmt.Printf("事件: %s, 数据: %s\n", event.Name, event.Data)
        return true  // 继续读取 (返回 false 停止)
    })
}

调试与故障排除

请求响应调试

Surf 提供了强大的调试功能,帮助开发者理解请求和响应的详细信息:

resp := surf.NewClient().
    Get("https://api.example.com").
    Do()

if resp.IsOk() {
    resp.Ok().Debug().
        Request().      // 显示请求详情
        Response(true). // 显示响应详情和体
        Print()
}

TLS 信息获取

你可以获取详细的 TLS 连接信息:

resp := surf.NewClient().Get("https://example.com").Do()
if resp.IsOk() {
    if tlsInfo := resp.Ok().TLSGrabber(); tlsInfo != nil {
        fmt.Printf("TLS 版本: %s\n", tlsInfo.Version)
        fmt.Printf("密码套件: %s\n", tlsInfo.CipherSuite)
        fmt.Printf("服务器名称: %s\n", tlsInfo.ServerName)

        for _, cert := range tlsInfo.PeerCertificates {
            fmt.Printf("证书 CN: %s\n", cert.Subject.CommonName)
        }
    }
}

性能优化策略

连接复用与单例模式

通过连接池和客户端复用,可以显著提升性能:

// 创建可重用的客户端
client := surf.NewClient().
    Builder().
    Singleton().      // 启用连接池
    Impersonate().
    Chrome().
    Build()

// 复用客户端进行多个请求
for i := 0; i < 100; i++ {
    resp := client.Get("https://api.example.com/data").Do()
    // 处理响应
}

// 完成后清理空闲连接
defer client.CloseIdleConnections()

响应缓存

对于需要多次访问响应体的场景,启用缓存可以提高效率:

client := surf.NewClient().
    Builder().
    CacheBody().      // 启用响应体缓存
    Build()

resp := client.Get("https://api.example.com/data").Do()
if resp.IsOk() {
    // 第一次访问从网络读取
    data1 := resp.Ok().Body.Bytes()

    // 后续访问使用缓存
    data2 := resp.Ok().Body.Bytes()  // 无网络 I/O
}

重试配置

配置自动重试逻辑,增强应用程序的健壮性:

client := surf.NewClient().
    Builder().
    Retry(3, 2*time.Second).           // 最多重试 3 次,每次等待 2 秒
    RetryCodes(http.StatusTooManyRequests, http.StatusServiceUnavailable).
    Build()

高级功能探索

H2C (HTTP/2 明文传输)

在某些内部网络环境中,你可能需要启用 HTTP/2 但不使用 TLS:

// 启用不带 TLS 的 HTTP/2
client := surf.NewClient().
    Builder().
    H2C().
    Build()

resp := client.Get("http://localhost:8080/h2c-endpoint").Do()

自定义头部顺序

精确控制头部顺序可以帮助避免某些指纹检测:

// 控制精确的头部顺序以规避指纹检测
headers := g.NewMapOrd[g.String, g.String]()
headers.Set("User-Agent", "Custom/1.0")
headers.Set("Accept", "*/*")
headers.Set("Accept-Language", "en-US")
headers.Set("Accept-Encoding", "gzip, deflate")

client := surf.NewClient().
    Builder().
    SetHeaders(headers).  // 头部将按此精确顺序发送
    Build()

自定义 DNS 解析器

指定自定义 DNS 解析器可以解决某些网络环境下的域名解析问题:

client := surf.NewClient().
    Builder().
    Resolver("8.8.8.8:53").  // 使用 Google DNS
    Build()

DNS-over-TLS

增强隐私保护,使用加密的 DNS 查询:

client := surf.NewClient().
    Builder().
    DNSOverTLS("1.1.1.1:853").  // Cloudflare DoT
    Build()

Unix 域套接字

与本地服务通信时,使用 Unix 域套接字可以提供更好的性能:

client := surf.NewClient().
    Builder().
    UnixDomainSocket("/var/run/docker.sock").
    Build()

resp := client.Get("http://localhost/v1.24/containers/json").Do()

网络接口绑定

在多网卡环境中,指定使用的网络接口:

client := surf.NewClient().
    Builder().
    InterfaceAddr("192.168.1.100").  // 绑定到特定 IP
    Build()

原始 HTTP 请求

对于特殊需求,可以直接发送原始 HTTP 请求:

rawRequest := `GET /api/data HTTP/1.1
Host: example.com
User-Agent: Custom/1.0
Accept: application/json

`

resp := surf.NewClient().
    Raw(g.String(rawRequest), "https").
    Do()

标准库兼容性

Surf 提供了与 Go 标准 net/http 包的无缝集成,允许你在任何期望标准 *http.Client 的第三方库中使用 Surf 的高级功能。

// 创建具有高级功能的 Surf 客户端
surfClient := surf.NewClient().
    Builder().
    Impersonate().Chrome().
    Session().
    Build()

// 转换为标准 net/http.Client
stdClient := surfClient.Std()

// 与任何第三方库一起使用
// 例如: AWS SDK, Google APIs, OpenAI client 等
resp, err := stdClient.Get("https://api.example.com")

使用 Std() 时保留的功能:

  • ✅ JA3/TLS 指纹
  • ✅ HTTP/2 设置
  • ✅ HTTP/3 & QUIC 指纹
  • ✅ 浏览器模拟头部
  • ✅ 有序头部
  • ✅ Cookies 和会话
  • ✅ 代理配置
  • ✅ 自定义头部和 User-Agent
  • ✅ 超时设置
  • ✅ 重定向策略
  • ✅ 请求/响应中间件

使用 Std() 时的限制:

  • ❌ 重试逻辑(需要在应用层实现)
  • ❌ 响应体缓存
  • ❌ 远程地址跟踪
  • ❌ 请求计时信息

总结

Surf 是一个功能强大且灵活的 HTTP 客户端库,为 Go 开发者提供了现代 Web 交互所需的一切工具。无论是简单的 API 调用还是复杂的浏览器模拟任务,Surf 都能提供优雅的解决方案。

其关键优势包括:

  • 完整的浏览器指纹模拟能力
  • 先进的 TLS 和 HTTP/3 支持
  • 优秀的性能和可靠性特性
  • 直观的 API 设计和完整的中间件系统
  • 与标准库的无缝集成

通过本文的介绍,你应该对 Surf 的主要功能和用法有了全面的了解。无论是初学者还是经验丰富的开发者,都能从 Surf 的强大功能中受益。


Made with ❤️ by the Surf contributors