Utiliser le SDK Go dans un gestionnaire Gin

Par solvethree5 min de lecture

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. 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 utilisez go get pour ajouter solvethree.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. 2.

    Définir les identifiants du serveur

    Définissez SOLVETHREE_API_KEY sur la clé API de votre espace de travail et INTEGRATION_KEY sur le secret que votre application interne enverra dans X-Integration-Key. Ces identifiants sont distincts : l’appelant de l’application n’a pas besoin de la clé API solvethree.

  3. 3.

    Configurer la cible fixe

    Définissez CAPTCHA_SITE sur le nom d’hôte cible et SOLVETHREE_PROXY sur 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 fixe Action à 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.

Gin · résolution limitée avec le SDK Go officiel
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. 1.

    Attribuer l’identifiant de requête avant d’appeler la route

    Faites conserver à l’appelant interne un X-Request-ID stable 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. 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. 3.

    Récupérer la tâche avant d’en créer une autre

    Si vous connaissez l’identifiant de tâche, appelez GetTask avec un nouveau contexte à durée limitée. Sinon, renvoyez la tâche d’origine via CreateTask avec 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.

Lancez votre première tâche.

Démarrez avec $5 de crédit dans votre espace de travail.

Créer un espace de travail
Utiliser le SDK Go dans un gestionnaire Gin · solvethree