Utiliser le SDK Go dans un gestionnaire Gin
Utilisez un seul client solvethree partagé et transmettez à Solve un contexte enfant de c.Request.Context() assorti d’une échéance. Conservez la configuration cible et la clé API sur le serveur, et authentifiez l’appelant de l’application avant de créer une tâche.
Sur cette page
Installer les dépendances et configurer la cible
- 1.
Créer le module Go et installer les dépendances
Utilisez Go 1.25 ou une version ultérieure pour la version actuelle de Gin. Le SDK solvethree lui-même nécessite Go 1.22+. Initialisez le module de votre application avec
go mod init, en utilisant votre propre chemin de module. Installez Gin en suivant son guide de démarrage rapide, puis utilisezgo getpour ajoutersolvethree.com/[email protected]. Le SDK officiel est distribué via le proxy public de modules hébergé sur le domaine ; il est servi depuis solvethree.com. - 2.
Définir les identifiants du serveur
Définissez
SOLVETHREE_API_KEYsur la clé API de votre espace de travail etINTEGRATION_KEYsur le secret que votre application interne enverra dansX-Integration-Key. Ces identifiants sont distincts : l’appelant de l’application n’a pas besoin de la clé API solvethree. - 3.
Configurer la cible fixe
Définissez
CAPTCHA_SITEsur le nom d’hôte cible etSOLVETHREE_PROXYsur le proxy utilisé pour la résolution. Créez d’abord un profil de site actif dans l’espace de travail ; consultez la configuration du profil de site. L’exemple fixeActionàlogin; modifiez donc cette valeur si votre intégration utilise une autre action. Définir le nom d’hôte et l’action ne crée pas de profil.
Ajouter la route Gin authentifiée
Le client est créé une seule fois et peut être utilisé sans risque pour des requêtes simultanées. La route vérifie l’identifiant de l’application interne avant d’appeler solvethree. Elle accepte un ID de requête fourni par l’appelant, mais pas une cible ou un proxy arbitraire.
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"))
}La tâche fournit Site, Action et un seul Proxy. Elle laisse Type et URL non définis, comme l’exige reCAPTCHA, et utilise le mode Enterprise v3 par défaut.
L’échéance explicite du contexte limite l’attente du gestionnaire à 180 secondes ; la déconnexion du client peut l’annuler plus tôt. Le serveur HTTP et tout proxy inverse doivent autoriser cette durée de requête. Dans le cas contraire, utilisez des opérations de création et de récupération distinctes plutôt que de maintenir cette route synchrone ouverte.
Le serveur écoute sur l’interface de bouclage. Intégrez la route à la configuration existante d’authentification interne et de déploiement de votre application ; n’exposez pas de point de terminaison de résolution payant sans authentifier l’appelant.
Gérer les erreurs sans exposer de secrets
Le gestionnaire utilise errors.As plutôt que de comparer des chaînes d’erreur. Une erreur terminale TaskFailedError produit une réponse 502 contenant l’ID de tâche et le code d’erreur. Les autres erreurs du SDK encapsulées produisent une réponse 502 contenant les ID de récupération. Le traitement de secours renvoie un message 400 fixe au lieu d’exposer des erreurs brutes, des identifiants ou des URL de proxy.
Ces réponses 502 ne signifient pas toutes que la résolution a échoué. Utilisez errors.Is pour distinguer une annulation d’une expiration du délai. Pour le traitement propre à HTTP, errors.As peut extraire une APIError imbriquée avec StatusCode et RetryAfter. Conservez cette distinction dans les diagnostics internes plutôt que de considérer chaque erreur comme une raison de créer une autre tâche.
Une tâche ayant atteint l’état terminal d’échec ne doit plus être interrogée. Récupérez-la si vous avez besoin du texte de son erreur, puis corrigez la cause avant de lancer une autre résolution. Les résolutions échouées sont remboursées.
Conserver les identifiants lorsque la requête expire
L’annulation met fin à l’attente, pas au travail distant. L’exemple renvoie les identifiants de récupération quand il le peut, mais ne les conserve pas durablement. Si l’appelant se déconnecte, cette réponse JSON peut ne jamais arriver.
- 1.
Attribuer l’identifiant de requête avant d’appeler la route
Faites conserver à l’appelant interne un
X-Request-IDstable pour chaque résolution logique. Les identifiants valides contiennent 1–64 lettres ASCII, chiffres, traits de soulignement ou traits d’union. Le SDK génère un identifiant s’il est absent, mais l’attribuer à l’avance permet une récupération même si la réponse est perdue. - 2.
Conserver les paramètres exacts de la tâche
Enregistrez le nom d’hôte, l’action, le proxy et l’identifiant de requête dans un stockage applicatif protégé. Une nouvelle tentative après une modification de la configuration de l’environnement ne doit pas remplacer silencieusement les paramètres de la tâche.
- 3.
Récupérer la tâche avant d’en créer une autre
Si vous connaissez l’identifiant de tâche, appelez
GetTaskavec un nouveau contexte à durée limitée. Sinon, renvoyez la tâche d’origine viaCreateTaskavec les mêmes identifiant de requête et paramètres. Cela renvoie la tâche existante ; des paramètres différents avec le même identifiant provoquent un conflit. Continuez à récupérer la tâche uniquement tant qu’elle est en attente ou en cours de résolution.
Solve ne crée la tâche qu’une fois et ne réessaie que les réponses temporaires aux interrogations portant le statut HTTP 429, 502, 503 ou 504, en respectant Retry-After dans les limites du délai du contexte. CreateTask ne réessaie jamais automatiquement un POST ; une expiration lors de la création nécessite donc une récupération plutôt qu’un nouvel identifiant de requête.
Envoyer le jeton avec l’identité renvoyée
Une réponse réussie du gestionnaire contient des données de solution privées destinées à l’appelant applicatif autorisé. Utilisez Solution.Token, et non l’identifiant de tâche, dans la requête cible. Utilisez les valeurs UserAgent et SecChUA renvoyées, et obtenez le proxy ayant réussi avec SuccessfulProxy(originalTask, readyResult).
Le SDK n’envoie rien à la cible. Une tâche prête signifie qu’une solution a été générée, pas que le site web l’a acceptée. Vérifiez séparément la réponse de la cible.
Sources et référence de l’API
Lancez votre première tâche.
Démarrez avec $5 de crédit dans votre espace de travail.