Llama a la API de CAPTCHA desde Spring Boot
Registra un único bean CaptchaClient en el servidor, crea una tarea una sola vez y consulta periódicamente su ID guardado. La clase auxiliar siguiente usa llamadas síncronas de Spring RestClient y devuelve respuestas Gson JsonObject.
En esta página
Añade las dependencias y registra la clase auxiliar
La clase auxiliar proporcionada usa Java 21+, Spring Web 7.0.10 y Gson 2.15.0. En un proyecto Spring Boot existente, conserva la versión compatible de Spring gestionada por Boot en lugar de sobrescribir solo spring-web para que coincida con el ejemplo. Añade Gson como dependencia si tu aplicación aún no lo incluye.
// Java 21+, Spring Web 7.0.10 and Gson 2.15.0; use your Boot dependency management.
// Save as CaptchaClient.java in your application's package.
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.http.HttpClient;
import java.time.Duration;
import org.springframework.http.MediaType;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
public final class CaptchaClient {
private final RestClient api;
public CaptchaClient(String key) {
var transport = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NEVER).build();
var factory = new JdkClientHttpRequestFactory(transport);
factory.setReadTimeout(Duration.ofSeconds(25));
api = RestClient.builder().baseUrl("https://api.solvethree.com/v1")
.requestFactory(factory).defaultHeader("Authorization", "Bearer " + key).build();
}
public JsonObject create(String site, String proxy, String requestId) {
var input = new JsonObject();
input.addProperty("site", site);
input.addProperty("action", "login");
input.addProperty("proxy", proxy);
input.addProperty("requestId", requestId); // Save before calling create.
String body = api.post().uri("/tasks?waitMs=0").contentType(MediaType.APPLICATION_JSON)
.body(input.toString()).retrieve().body(String.class);
return JsonParser.parseString(body).getAsJsonObject();
}
public JsonObject get(String id) {
if (!id.matches("[A-Za-z0-9_-]+")) throw new IllegalArgumentException("Invalid task ID");
String body = api.get().uri("/tasks/{id}?waitMs=15000", id)
.retrieve().body(String.class);
return JsonParser.parseString(body).getAsJsonObject();
}
}
// Construct once with System.getenv("SOLVETHREE_API_KEY") in a server-side @Bean.
// Call create once, save its id, then get(id) until ready/failed or your deadline.
// RestClient throws on HTTP errors; keep the saved requestId and any known task id.Guarda la clase como CaptchaClient.java en el paquete de tu aplicación. En un método de fábrica @Bean del servidor, crea una única instancia usando la variable de entorno SOLVETHREE_API_KEY. Comprueba al iniciar que la clave esté configurada. La clase auxiliar la añade como cabecera de autorización Bearer; no la incluyas en el código del navegador.
Reutiliza ese bean mediante inyección por constructor. RestClient se puede reutilizar entre hilos, pero cada solicitud bloquea el hilo que la realiza. No invoques estos métodos en un bucle de eventos de WebFlux. La documentación del cliente REST de Spring describe el cliente síncrono.
El transporte usa un tiempo de espera de conexión de 10 segundos y de lectura de 25 segundos, sin redirecciones. Las respuestas se leen como cadenas y se analizan con Gson, en lugar de asignarse a objetos de respuesta tipados.
Configura el sitio, la acción y el proxy
Antes de llamar a create, configura un perfil activo para el sitio de destino en tu espacio de trabajo. Enviar un nombre de host y una acción no crea ese perfil. Consulta la configuración del perfil del sitio si el sitio aún no está configurado.
- Pasa el nombre de host como
site, no una URL de página completa. Una solicitud de reCAPTCHA no tiene camposurlnitype. - La clase auxiliar fija
actionenlogin. Cambia ese valor o conviértelo en un parámetro del método si la solicitud prevista usa una acción diferente. - Pasa una única URL de proxy. La API requiere exactamente uno de los campos
proxyoproxyCandidates; esta clase auxiliar implementa la opción de proxy único. - La clase auxiliar omite
recaptchaType, por lo que la API usa su valor predeterminadoenterprise-v3.
Crea una sola vez y consulta periódicamente el ID de tarea guardado
- 1.
Guarda un ID de solicitud antes de crear la tarea
Elige un
requestIdque contenga entre 1–64 letras ASCII, números, guiones bajos o guiones. Guárdalo junto con los datos de entrada de la tarea antes de llamar acreate. Te permite recuperar la misma tarea si se pierde la respuesta de creación. - 2.
Llama a create y guarda el id devuelto
Llama al método
createdel bean con el nombre de host, el proxy y el ID de solicitud guardado. Envía un único POST a/v1/tasksconwaitMs=0. Guarda eliddevuelto; usa ese ID de tarea, no el ID de solicitud, para las consultas posteriores. - 3.
Llama a get hasta que la tarea alcance un estado terminal
Pasa el ID de tarea guardado a
get. Cada consulta solicitawaitMs=15000y bloquea el hilo mientras espera la respuesta. Continúa si el estado espendingosolving, dentro de un plazo límite definido por la aplicación. Detente si esreadyofailed. Los tiempos de espera HTTP limitan las solicitudes individuales, no todo el bucle de consulta. - 4.
Lee la solución solo cuando esté lista
Para reCAPTCHA, envía
solution.tokenal destino previsto, no el ID de tarea. Usa los valores devueltos deuserAgentysecChUacon el mismo proxy con el que se resolvió correctamente. No los sustituyas por cabeceras de navegador ajenas ni cambies la URL de destino. Una tarea lista proporciona una solución; no confirma que el destino haya aceptado tu solicitud posterior.
Gestiona los errores HTTP por separado de las tareas fallidas
- La llamada de creación agota el tiempo de espera antes de que recibas un ID de tarea.
Es posible que el servidor haya creado la tarea aunque tu cliente no haya recibido la respuesta.
Prueba esto: Recupera la tarea repitiendo la misma solicitud con el
requestIdguardado. Si los datos de entrada coinciden, se devuelve la tarea existente. No generes un nuevo ID de solicitud a menos que quieras crear una nueva tarea lógica.- Una llamada a get falla en la capa HTTP.
RestClient.retrieve()lanza una excepción ante respuestas HTTP que no indican éxito. Eso no equivale a un estado de tareafailed.Prueba esto: Gestiona el error HTTP antes de intentar leer el contenido de una respuesta correcta. Conserva el ID de tarea conocido para recuperarla en lugar de crear otra. Diagnostica los datos de entrada no válidos antes de reintentarlos sin cambios.
- La respuesta de la tarea tiene el estado
failed. Lee sus campos
errorCodeyerror;site-unreachablees uno de los posibles códigos de error de tarea.Prueba esto: Deja de consultar esa tarea y soluciona la causa indicada antes de iniciar otra. Las resoluciones fallidas se reembolsan; no supongas que el fallo significa que no hay saldo suficiente.
- Reutilizar un ID de solicitud provoca un conflicto.
Compara los nuevos datos de entrada de la tarea con los guardados para ese ID de solicitud.
Prueba esto: Usa los datos de entrada originales para recuperar la tarea existente. Usa un nuevo ID de solicitud cuando los datos de entrada de la tarea sean distintos de forma intencionada.
Para interpretar los errores, consulta Errores de la API de CAPTCHA.
Fuentes y referencia de la API
Ejecuta tu primera tarea.
Empieza con $5 de crédito en tu espacio de trabajo.