在 net/http 服务器中使用 Go SDK
创建一个共享的 solvethree 客户端,通过经过身份验证的 POST 返回任务 ID,再通过独立的 GET 查询任务状态。不要在创建处理函数中调用 Solve:此集成让调用方无需保持原始请求连接,即可等待结果。
本页内容
配置服务器和目标
- 1.
安装 Go SDK
使用 Go 1.22 或更高版本。在已初始化的 Go 模块中,使用
go get solvethree.com/[email protected]安装官方 SDK。将以下示例保存为main.go。 - 2.
设置服务器环境
将
SOLVETHREE_API_KEY设为工作区 API 密钥,将INTEGRATION_KEY设为供此内部服务器调用方使用的独立密钥。将CAPTCHA_SITE设为目标主机名,将SOLVETHREE_PROXY设为求解所用的 HTTP 或 HTTPS 代理 URL。两项密钥都应保存在可信服务器上。 - 3.
准备已配置的目标
确保你的工作区有该站点的可用活跃配置;请参阅站点配置设置。示例将操作固定为
login。运行服务器前,请将其更改为目标所需的操作。提供主机名和操作不会创建配置。
package main
import (
"context"
"encoding/json"
"errors"
"log"
"net/http"
"os"
"time"
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") }
authorize := func(w http.ResponseWriter, r *http.Request) bool {
if r.Header.Get("X-Integration-Key") != secret { http.Error(w, "Unauthorized", 401); return false }
return true
}
respond := func(w http.ResponseWriter, result *solvethree.TaskResult, err error) {
w.Header().Set("Content-Type", "application/json")
if err != nil {
var recovery *solvethree.Error
w.WriteHeader(http.StatusBadGateway)
ids := map[string]string{"error": "Solver request failed"}
if errors.As(err, &recovery) { ids["requestId"] = recovery.RequestID; ids["taskId"] = recovery.TaskID }
_ = json.NewEncoder(w).Encode(ids)
return
}
_ = json.NewEncoder(w).Encode(result)
}
mux := http.NewServeMux()
mux.HandleFunc("POST /captcha/tasks", func(w http.ResponseWriter, r *http.Request) {
if !authorize(w,r) { return }
input := solvethree.TaskRequest{Site: os.Getenv("CAPTCHA_SITE"), Action:"login",
Proxy:os.Getenv("SOLVETHREE_PROXY"), RequestID:r.Header.Get("X-Request-ID")}
if err := input.Validate(); err != nil { http.Error(w,"Invalid task input",400);return }
ctx,cancel := context.WithTimeout(r.Context(),20*time.Second);defer cancel()
zero:=0
result,err:=client.CreateTask(ctx,input,&zero)
respond(w,result,err)
})
mux.HandleFunc("GET /captcha/tasks/{id}", func(w http.ResponseWriter, r *http.Request) {
if !authorize(w,r) { return }
ctx,cancel:=context.WithTimeout(r.Context(),25*time.Second);defer cancel()
result,err:=client.GetTask(ctx,r.PathValue("id"),15000)
respond(w,result,err)
})
server:=&http.Server{Addr:"127.0.0.1:3000", Handler:mux, ReadHeaderTimeout:5*time.Second}
log.Fatal(server.ListenAndServe())
}使用 go run . 运行模块。服务器监听 127.0.0.1:3000。它使用 Go 标准 net/http 路由器,因此无需框架。SDK 客户端只创建一次,可安全地并发使用。
任务使用默认的 enterprise-v3 reCAPTCHA 模式。它提供站点主机名、操作和单个代理,而不是 type 或 url。POST 请求体不会被使用,因此调用方无法选择任意目标或代理。
发送一次 POST 并保存任务 ID
发送 POST /captcha/tasks,并附带 X-Integration-Key 请求头。同时发送由调用方生成的 X-Request-ID,以便在收到任务 ID 前连接断开时找回任务。使用 1–64 个 ASCII 字母、数字、下划线或连字符。
处理函数会验证已配置的任务,然后以零等待值调用 CreateTask。它请求创建任务,但不等待求解完成。其 20 秒上下文限制的是此 HTTP 请求的等待时长,而不是求解超时时间。
成功后,处理函数返回 SDK 任务结果。保存其中的任务 ID,并使用 GET 路由进行后续查询。不要将 POST 成功视为已获得可用令牌。
两个路由都需要集成密钥。这是可信的内部接口,并非按用户授权:持有该密钥的调用方通过已配置的工作区共享访问权限。
通过 GET 查询现有任务,直到完成
发送 GET /captcha/tasks/{id},并附带相同的集成密钥请求头。处理函数只调用 GetTask,绝不会创建替代任务。它会在 25 秒的请求上下文内请求最多等待 15 秒。
pending或solving:保留相同的任务 ID,再次查询。ready:读取解决方案。这是唯一包含可用结果的状态。failed:停止轮询并检查errorCode和error。先修正原因,再决定是否创建另一个任务。
在解码成功的任务结果前,先检查 HTTP 响应状态。在此服务器中,未授权请求返回 401,任务输入无效返回 400,SDK 请求错误返回 502。返回任务的状态为 failed,与 HTTP 请求失败是不同的结果。
超时后找回任务,避免再次求解
超时不能证明创建失败。取消请求上下文只会停止本地等待,不会停止远程任务。SDK 从不自动重试用于创建任务的 POST。
- 1.
如果有任务 ID,查询该任务
使用该 ID 调用 GET 路由。发生 SDK 错误时,如果 SDK 提供了
taskId和requestId,示例的 JSON 错误响应就会包含这两个字段。 - 2.
如果只有请求 ID,重放原始创建请求
使用相同的
X-Request-ID和未更改的任务输入再次发送 POST。这意味着保持已配置的主机名、操作和代理不变。相同的请求 ID 和任务请求会找回现有任务;使用该 ID 但输入不同会产生冲突。 - 3.
在首次请求前保存 ID
如果未提供请求 ID,SDK 会生成一个,但已断开连接的调用方可能永远收不到它。在 POST 前选定并保存
X-Request-ID,就无需依赖错误响应来找回任务。
使用相同代理提交就绪结果
此服务器会返回结果;SDK 不会将结果提交给目标。你的提交代码必须使用令牌、返回的 userAgent 和 secChUa 浏览器身份,以及求解成功时所用的代理。在这个单代理示例中,请继续使用已配置的代理,不要在求解后切换 IP。
ready 任务表示已生成解决方案,并不表示目标接受了你的应用请求。如果提交失败,请先检查发出的令牌、身份信息、代理和目标请求,再付费进行另一次求解。
运行您的第一个任务。
使用 $5 工作区额度开始体验。