在 net/http 服务器中使用 Go SDK

作者:solvethree阅读需 1 分钟

创建一个共享的 solvethree 客户端,通过经过身份验证的 POST 返回任务 ID,再通过独立的 GET 查询任务状态。不要在创建处理函数中调用 Solve:此集成让调用方无需保持原始请求连接,即可等待结果。

本页内容

配置服务器和目标

  1. 1.

    安装 Go SDK

    使用 Go 1.22 或更高版本。在已初始化的 Go 模块中,使用 go get solvethree.com/[email protected] 安装官方 SDK。将以下示例保存为 main.go。

  2. 2.

    设置服务器环境

    将 SOLVETHREE_API_KEY 设为工作区 API 密钥,将 INTEGRATION_KEY 设为供此内部服务器调用方使用的独立密钥。将 CAPTCHA_SITE 设为目标主机名,将 SOLVETHREE_PROXY 设为求解所用的 HTTP 或 HTTPS 代理 URL。两项密钥都应保存在可信服务器上。

  3. 3.

    准备已配置的目标

    确保你的工作区有该站点的可用活跃配置;请参阅站点配置设置。示例将操作固定为 login。运行服务器前,请将其更改为目标所需的操作。提供主机名和操作不会创建配置。

Go net/http · 创建并获取任务
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. 1.

    如果有任务 ID,查询该任务

    使用该 ID 调用 GET 路由。发生 SDK 错误时,如果 SDK 提供了 taskId 和 requestId,示例的 JSON 错误响应就会包含这两个字段。

  2. 2.

    如果只有请求 ID,重放原始创建请求

    使用相同的 X-Request-ID 和未更改的任务输入再次发送 POST。这意味着保持已配置的主机名、操作和代理不变。相同的请求 ID 和任务请求会找回现有任务;使用该 ID 但输入不同会产生冲突。

  3. 3.

    在首次请求前保存 ID

    如果未提供请求 ID,SDK 会生成一个,但已断开连接的调用方可能永远收不到它。在 POST 前选定并保存 X-Request-ID,就无需依赖错误响应来找回任务。

使用相同代理提交就绪结果

此服务器会返回结果;SDK 不会将结果提交给目标。你的提交代码必须使用令牌、返回的 userAgent 和 secChUa 浏览器身份,以及求解成功时所用的代理。在这个单代理示例中,请继续使用已配置的代理,不要在求解后切换 IP。

ready 任务表示已生成解决方案,并不表示目标接受了你的应用请求。如果提交失败,请先检查发出的令牌、身份信息、代理和目标请求,再付费进行另一次求解。

运行您的第一个任务。

使用 $5 工作区额度开始体验。

创建工作区
在 net/http 服务器中使用 Go SDK · solvethree