在 Gin 处理程序中使用 Go SDK
使用一个共享的 solvethree 客户端,并将派生自 c.Request.Context() 且设置了截止时间的子上下文传给 Solve。将目标配置和 API 密钥保留在服务端,并在创建任务前对应用调用方进行身份验证。
本页内容
安装依赖并配置目标
- 1.
创建 Go 模块并安装依赖
当前 Gin 版本请使用 Go 1.25 或更高版本。solvethree SDK 本身要求 Go 1.22+。使用
go mod init和你自己的模块路径初始化应用模块。按照 Gin 快速入门安装 Gin,然后使用go get添加solvethree.com/[email protected]。官方 SDK 通过域名托管的公共模块代理提供;其来源是 solvethree.com。 - 2.
设置服务端凭据
将
SOLVETHREE_API_KEY设为工作区 API 密钥,并将INTEGRATION_KEY设为内部应用将在X-Integration-Key中发送的密钥。这是两套独立的凭据:应用调用方不需要 solvethree API 密钥。 - 3.
配置固定目标
将
CAPTCHA_SITE设为目标主机名,将SOLVETHREE_PROXY设为求解使用的代理。先在工作区中创建一个已启用的站点配置文件;请参阅站点配置文件设置。示例将Action固定为login,如果集成使用其他操作,请修改该值。设置主机名和操作不会创建配置文件。
添加需要身份验证的 Gin 路由
客户端仅创建一次,可安全地用于并发请求。路由会在调用 solvethree 前检查内部应用凭据。它接受调用方提供的请求 ID,但不接受任意目标或代理。
package main
import (
"context"
"errors"
"log"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
solvethree "solvethree.com/sdk"
)
func main() {
client,err:=solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"),nil)
if err!=nil { log.Fatal(err) }
secret:=os.Getenv("INTEGRATION_KEY")
if secret=="" { log.Fatal("Set INTEGRATION_KEY") }
router:=gin.New()
router.Use(gin.Recovery())
router.POST("/captcha/solve",func(c *gin.Context){
if c.GetHeader("X-Integration-Key")!=secret { c.Status(http.StatusUnauthorized);return }
input:=solvethree.TaskRequest{Site:os.Getenv("CAPTCHA_SITE"),Action:"login",
Proxy:os.Getenv("SOLVETHREE_PROXY"),RequestID:c.GetHeader("X-Request-ID")}
ctx,cancel:=context.WithTimeout(c.Request.Context(),180*time.Second);defer cancel()
result,err:=client.Solve(ctx,input,solvethree.SolveOptions{})
if err!=nil {
var failed *solvethree.TaskFailedError
var recovery *solvethree.Error
if errors.As(err,&failed) { c.JSON(502,gin.H{"taskId":failed.TaskID,"errorCode":failed.ErrorCode});return }
if errors.As(err,&recovery) { c.JSON(502,gin.H{"requestId":recovery.RequestID,"taskId":recovery.TaskID});return }
c.JSON(400,gin.H{"error":"Invalid task input"});return
}
// Return private solution data only to the authorized application caller.
c.JSON(200,result)
})
log.Fatal(router.Run("127.0.0.1:3000"))
}任务提供 Site、Action 和单个 Proxy。按照 reCAPTCHA 的要求,不设置 Type 和 URL,并使用默认的 Enterprise v3 模式。
显式设置的上下文截止时间将处理函数的等待时间限制为 180 秒;客户端断开连接可能使其提前取消。HTTP 服务器和所有反向代理都必须允许这一请求时长。如果无法允许,请使用独立的创建和查询操作,而不是让此同步路由一直保持连接。
监听器绑定到回环地址。请将该路由集成到应用现有的内部身份验证和部署设置中;不要在未验证调用方身份的情况下对外暴露付费求解端点。
处理错误时避免泄露机密信息
处理函数使用 errors.As,而不是匹配错误字符串。表示任务最终失败的 TaskFailedError 会生成包含任务 ID 和错误码的 502 响应。其他经过包装的 SDK 错误会生成包含恢复所需 ID 的 502 响应。兜底处理会返回固定的 400 消息,而不是暴露原始错误、凭据或代理 URL。
这些 502 响应并不都意味着求解失败。使用 errors.Is 区分取消和截止时间到期。对于 HTTP 特定处理,可通过 errors.As 提取嵌套的 APIError,其中包含 StatusCode 和 RetryAfter。应在内部诊断中保留这种区分,而不是将每个错误都视为创建新任务的理由。
已进入失败终态的任务不应再次轮询。如需错误文本,可获取该任务,然后在开始下一次求解之前修正原因。求解失败会退款。
请求超时时保留 ID
取消只会停止等待,不会停止远程工作。示例会在可能时返回恢复所需的 ID,但不会持久化保存它们。如果调用方断开连接,该 JSON 响应可能永远无法送达。
- 1.
调用路由前分配请求 ID
让内部调用方为每次逻辑求解保留稳定的
X-Request-ID。有效 ID 包含 1–64 个 ASCII 字母、数字、下划线或连字符。缺少 ID 时,SDK 会生成一个,但提前分配 ID 可确保即使响应丢失也能恢复。 - 2.
保留完整且一致的任务输入
将主机名、操作、代理和请求 ID 存储在受保护的应用存储中。环境配置更改后重试时,不得在未明确告知的情况下替换为不同的任务输入。
- 3.
先恢复,再创建新任务
如果已知任务 ID,使用新的、有时限的上下文调用
GetTask。如果没有任务 ID,则使用相同的请求 ID 和输入,通过CreateTask重新提交原始任务。这会返回现有任务;相同 ID 搭配不同输入会产生冲突。仅在任务处于等待或求解中状态时继续获取。
Solve 只创建一次,并且仅重试 HTTP 状态为 429、502、503 或 504 的临时轮询响应,在上下文截止时间内遵循 Retry-After。CreateTask 从不自动重试 POST,因此创建超时后仍需恢复,而不是使用新的请求 ID。
使用返回的身份信息提交令牌
处理函数成功响应中包含供已授权应用调用方使用的私密求解数据。在目标请求中使用 Solution.Token,而不是任务 ID。使用返回的 UserAgent 和 SecChUA,并通过 SuccessfulProxy(originalTask, readyResult) 获取成功求解所用的代理。
SDK 不会向目标提交任何内容。任务就绪表示已生成求解结果,并不表示网站已接受它。请单独检查目标的响应。
来源与 API 参考
运行您的第一个任务。
使用 $5 工作区额度开始体验。