Use o SDK de Go em um handler do Gin

Por solvethree5 min de leitura

Use um único cliente solvethree compartilhado e passe a Solve um contexto filho de c.Request.Context() com prazo definido. Mantenha a configuração do destino e a chave de API no servidor e autentique o chamador da aplicação antes de criar uma tarefa.

Nesta página

Instale as dependências e configure o destino

  1. 1.

    Crie o módulo Go e instale as dependências

    Use Go 1.25 ou posterior para a versão atual do Gin. O SDK do solvethree exige Go 1.22+. Inicialize o módulo da sua aplicação com go mod init, usando seu próprio caminho de módulo. Instale o Gin seguindo o guia de início rápido e use go get para adicionar solvethree.com/[email protected]. O SDK oficial é distribuído pelo proxy público de módulos hospedado no domínio; ele é servido a partir de solvethree.com.

  2. 2.

    Defina as credenciais do servidor

    Defina SOLVETHREE_API_KEY com a chave de API do seu workspace e INTEGRATION_KEY com o segredo que sua aplicação interna enviará em X-Integration-Key. São credenciais separadas: o chamador da aplicação não precisa da chave de API do solvethree.

  3. 3.

    Configure o destino fixo

    Defina CAPTCHA_SITE com o nome do host de destino e SOLVETHREE_PROXY com o proxy usado na resolução. Primeiro, crie um perfil de site ativo no workspace; consulte a configuração do perfil de site. O exemplo fixa Action como login, então altere esse valor se sua integração usar outra ação. Definir o nome do host e a ação não cria um perfil.

Adicione a rota autenticada do Gin

O cliente é criado uma única vez e é seguro para requisições simultâneas. A rota verifica a credencial da aplicação interna antes de chamar solvethree. Ela aceita um ID de requisição do chamador, mas não um destino ou proxy arbitrário.

Gin · resolução com limites usando o SDK oficial de Go
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"))
}

A tarefa fornece Site, Action e um único Proxy. Ela deixa Type e URL sem definição, conforme exigido para reCAPTCHA, e usa o modo padrão Enterprise v3.

O prazo explícito do contexto limita a espera do handler a 180 segundos; a desconexão do cliente pode cancelá-la antes. O servidor HTTP e qualquer proxy reverso devem permitir essa duração de requisição. Se não puderem, use operações separadas de criação e consulta em vez de manter essa rota síncrona aberta.

O listener fica vinculado ao endereço de loopback. Integre a rota à configuração existente de autenticação interna e implantação da sua aplicação; não exponha um endpoint de resolução paga sem autenticar o chamador.

Trate erros sem expor segredos

O handler usa errors.As em vez de comparar strings de erro. Um TaskFailedError terminal produz uma resposta 502 contendo o ID da tarefa e o código de erro. Outros erros encapsulados do SDK produzem uma resposta 502 contendo IDs de recuperação. O fallback retorna uma mensagem fixa com status 400 em vez de expor erros brutos, credenciais ou URLs de proxy.

Nem todas essas respostas 502 significam que a resolução falhou. Use errors.Is para distinguir cancelamento de expiração do prazo. Para tratamento específico de HTTP, errors.As pode extrair um APIError aninhado com StatusCode e RetryAfter. Mantenha essa distinção nos diagnósticos internos, em vez de tratar cada erro como motivo para criar outra tarefa.

Não consulte novamente uma tarefa que terminou com falha. Recupere-a se precisar do texto do erro e corrija a causa antes de iniciar outra resolução. Resoluções com falha são reembolsadas.

Guarde os IDs quando a solicitação exceder o tempo limite

O cancelamento interrompe a espera, não o trabalho remoto. O exemplo retorna IDs de recuperação quando possível, mas não os persiste. Se o chamador se desconectar, essa resposta JSON talvez nunca chegue.

  1. 1.

    Atribua o ID da solicitação antes de chamar a rota

    Faça o chamador interno manter um X-Request-ID estável para cada resolução lógica. IDs válidos contêm de 1–64 letras ASCII, números, sublinhados ou hífens. O SDK gera um ID quando ele não é fornecido, mas atribuí-lo antecipadamente permite a recuperação mesmo se a resposta se perder.

  2. 2.

    Guarde os dados de entrada exatos da tarefa

    Armazene o hostname, a ação, o proxy e o ID da solicitação em um armazenamento protegido da aplicação. Uma nova tentativa após uma alteração na configuração do ambiente não deve substituir silenciosamente os dados de entrada da tarefa.

  3. 3.

    Recupere antes de criar novo trabalho

    Se o ID da tarefa for conhecido, chame GetTask usando um novo contexto com prazo limitado. Caso contrário, reenvie a tarefa original por CreateTask com o mesmo ID de solicitação e os mesmos dados de entrada. Isso retorna a tarefa existente; dados diferentes com o mesmo ID geram conflito. Continue consultando apenas enquanto a tarefa estiver pendente ou em resolução.

Solve cria uma única vez e repete apenas consultas que recebem respostas temporárias com status HTTP 429, 502, 503 ou 504, respeitando Retry-After dentro do prazo do contexto. CreateTask nunca repete POST automaticamente, portanto, um tempo limite na criação ainda exige recuperação, não um novo ID de solicitação.

Envie o token com a identidade retornada

Uma resposta bem-sucedida do handler contém dados privados da solução para o chamador autorizado da aplicação. Use Solution.Token, não o ID da tarefa, na solicitação ao destino. Use os valores retornados de UserAgent e SecChUA e obtenha o proxy bem-sucedido com SuccessfulProxy(originalTask, readyResult).

O SDK não envia nada ao destino. Uma tarefa pronta significa que uma solução foi gerada, não que o site a aceitou. Verifique a resposta do destino separadamente.

Execute sua primeira tarefa.

Comece com $5 em créditos no espaço de trabalho.

Criar um espaço de trabalho
Use o SDK de Go em um handler do Gin · solvethree