Usa el SDK de Go en un servidor net/http

Por solvethree5 min de lectura

Crea un único cliente compartido de solvethree, devuelve el ID de tarea desde un POST autenticado y obtén su estado mediante un GET separado. No llames a Solve dentro del manejador de creación: esta integración permite al cliente esperar el resultado sin mantener abierta la solicitud original.

En esta página

Configura el servidor y el destino

  1. 1.

    Instala el SDK de Go

    Usa Go 1.22 o posterior. En un módulo Go inicializado, instala el SDK oficial con go get solvethree.com/[email protected]. Guarda el ejemplo siguiente como main.go.

  2. 2.

    Configura el entorno del servidor

    Establece SOLVETHREE_API_KEY con la clave de API de tu espacio de trabajo e INTEGRATION_KEY con un secreto independiente para los clientes de este servidor interno. Establece CAPTCHA_SITE con el nombre de host del destino y SOLVETHREE_PROXY con la URL del proxy HTTP o HTTPS usado para la resolución. Mantén ambas claves en servidores de confianza.

  3. 3.

    Prepara el destino configurado

    Asegúrate de que el sitio tenga un perfil activo disponible para tu espacio de trabajo; consulta la configuración de perfiles de sitio. El ejemplo fija la acción en login. Cámbiala por la acción que espera tu destino antes de ejecutar el servidor. Proporcionar un nombre de host y una acción no crea un perfil.

Go net/http · crear y recuperar tareas
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())
}

Ejecuta el módulo con go run .. El servidor escucha en 127.0.0.1:3000. Usa el enrutador estándar net/http de Go, por lo que no requiere ningún framework. El cliente SDK se crea una sola vez y es seguro para uso concurrente.

La tarea usa el modo de reCAPTCHA predeterminado enterprise-v3. Proporciona un nombre de host del sitio, una acción y un único proxy, no un type ni una url. El cuerpo del POST no se usa, por lo que los clientes no pueden seleccionar destinos ni proxies arbitrarios.

Envía un POST una vez y guarda el ID de tarea

Envía POST /captcha/tasks con la cabecera X-Integration-Key. Envía también un X-Request-ID generado por el cliente para poder recuperar la tarea si la conexión termina antes de recibir su ID. Usa entre 1–64 letras ASCII, números, guiones bajos o guiones.

El manejador valida la tarea configurada y después llama a CreateTask con un valor de espera de cero. Solicita la creación de la tarea sin esperar a que termine la resolución. Su contexto de 20 segundos limita cuánto espera esta solicitud HTTP; no es un tiempo de espera de la resolución.

Si la operación tiene éxito, el manejador devuelve el resultado de tarea del SDK. Guarda su ID de tarea y usa la ruta GET para las comprobaciones posteriores. No interpretes un POST exitoso como un token utilizable.

Ambas rutas requieren la clave de integración. Es una interfaz interna de confianza, no una autorización por usuario: los clientes que tienen esa clave comparten el acceso a través del espacio de trabajo configurado.

Consulta la tarea existente con GET hasta que termine

Envía GET /captcha/tasks/{id} con la misma cabecera de clave de integración. El manejador solo llama a GetTask; nunca crea una tarea de reemplazo. Solicita hasta 15 segundos de espera dentro de un contexto de solicitud de 25 segundos.

  • pending o solving: conserva el mismo ID de tarea y vuelve a obtenerla.
  • ready: lee la solución. Es el único estado con un resultado utilizable.
  • failed: deja de consultar el estado e inspecciona errorCode y error. Corrige la causa antes de decidir si crear otra tarea.

Comprueba el estado de la respuesta HTTP antes de decodificar un resultado de tarea exitoso. En este servidor, las solicitudes no autorizadas devuelven 401, los datos de entrada de tarea no válidos devuelven 400 y los errores de solicitud del SDK devuelven 502. Una tarea devuelta cuyo estado es failed es un resultado distinto de un fallo en la solicitud HTTP.

Recupérate de un tiempo de espera agotado sin crear otra resolución

Un tiempo de espera agotado no demuestra que la creación haya fallado. Cancelar el contexto de la solicitud detiene la espera local, no la tarea remota. El SDK nunca reintenta automáticamente el POST de creación.

  1. 1.

    Si tienes un ID de tarea, obtén la tarea

    Usa la ruta GET con ese ID. En caso de errores del SDK, la respuesta de error JSON del ejemplo incluye taskId y requestId cuando el SDK los expone.

  2. 2.

    Si solo tienes el ID de solicitud, repite la creación original

    Envía de nuevo el POST con el mismo X-Request-ID y sin cambiar los datos de entrada de la tarea. Esto significa mantener sin cambios el nombre de host, la acción y el proxy configurados. El mismo ID de solicitud y la misma solicitud de tarea recuperan la tarea existente; usar datos de entrada distintos con ese ID provoca un conflicto.

  3. 3.

    Guarda el ID antes de la primera solicitud

    El SDK genera un ID de solicitud cuando no se proporciona uno, pero un cliente desconectado puede no llegar a recibirlo. Elegir y conservar X-Request-ID antes del POST evita depender de la respuesta de error para la recuperación.

Usa el resultado listo con el mismo proxy

Este servidor devuelve el resultado; el SDK no lo envía al destino. Tu código de envío debe usar el token, la identidad del navegador devuelta en userAgent y secChUa, y el proxy que funcionó. En este ejemplo con un único proxy, sigue usando el proxy configurado en lugar de cambiar de IP después de la resolución.

Una tarea ready significa que se generó una solución, no que el destino aceptara la solicitud de tu aplicación. Si el envío falla, inspecciona el token saliente, la identidad, el proxy y la solicitud al destino antes de pagar por otra resolución.

Ejecuta tu primera tarea.

Empieza con $5 de crédito en tu espacio de trabajo.

Crear un espacio de trabajo
Usa el SDK de Go en un servidor net/http · solvethree