Usa el SDK de Go en un servidor net/http
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.
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 comomain.go. - 2.
Configura el entorno del servidor
Establece
SOLVETHREE_API_KEYcon la clave de API de tu espacio de trabajo eINTEGRATION_KEYcon un secreto independiente para los clientes de este servidor interno. EstableceCAPTCHA_SITEcon el nombre de host del destino ySOLVETHREE_PROXYcon la URL del proxy HTTP o HTTPS usado para la resolución. Mantén ambas claves en servidores de confianza. - 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.
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.
pendingosolving: 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 inspeccionaerrorCodeyerror. 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.
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
taskIdyrequestIdcuando el SDK los expone. - 2.
Si solo tienes el ID de solicitud, repite la creación original
Envía de nuevo el POST con el mismo
X-Request-IDy 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.
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-IDantes 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.
Fuentes y referencia de la API
Ejecuta tu primera tarea.
Empieza con $5 de crédito en tu espacio de trabajo.