Используйте Go SDK в сервере net/http

Автор: solvethree4 мин на чтение

Создайте один общий клиент solvethree, возвращайте ID задачи из аутентифицированного POST-запроса и получайте ее статус через отдельный GET. Не вызывайте Solve внутри обработчика создания: эта интеграция позволяет вызывающей стороне дождаться результата, не удерживая исходный запрос открытым.

На этой странице

Настройте сервер и целевой сайт

  1. 1.

    Установите SDK для Go

    Используйте Go 1.22 или новее. В инициализированном модуле Go установите официальный SDK командой go get solvethree.com/[email protected]. Сохраните пример ниже как main.go.

  2. 2.

    Настройте окружение сервера

    Задайте в SOLVETHREE_API_KEY API-ключ рабочего пространства, а в INTEGRATION_KEY — отдельный секрет для клиентов этого внутреннего сервера. В CAPTCHA_SITE укажите имя хоста целевого сайта, а в SOLVETHREE_PROXY — URL HTTP- или HTTPS-прокси, используемого для решения. Храните оба ключа на доверенных серверах.

  3. 3.

    Подготовьте настроенный целевой сайт

    Убедитесь, что у сайта есть активный профиль, доступный вашему рабочему пространству; см. настройку профиля сайта. В примере действие фиксировано и равно login. Перед запуском сервера замените его на действие, которое ожидает целевой сайт. Указание имени хоста и действия не создает профиль.

Go net/http · создание и получение задач
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())
}

Запустите модуль командой go run .. Сервер слушает на 127.0.0.1:3000. Он использует стандартный маршрутизатор Go net/http, поэтому фреймворк не требуется. Клиент SDK создается один раз и безопасен для конкурентного использования.

Задача использует режим reCAPTCHA по умолчанию — enterprise-v3. В ней указываются имя хоста сайта, действие и один прокси, а не type или url. Тело POST-запроса не используется, поэтому вызывающая сторона не может выбирать произвольные целевые сайты или прокси.

Отправьте POST один раз и сохраните ID задачи

Отправьте POST /captcha/tasks с заголовком X-Integration-Key. Также передайте сгенерированный вызывающей стороной X-Request-ID, чтобы восстановить задачу, если соединение прервется до получения ее ID. Используйте 1–64 символа: ASCII-буквы, цифры, подчеркивания или дефисы.

Обработчик проверяет настроенную задачу, затем вызывает CreateTask с нулевым значением ожидания. Он запрашивает создание задачи, не дожидаясь завершения решения. Контекст на 20 секунд ограничивает время ожидания этого HTTP-запроса; это не тайм-аут решения.

При успехе обработчик возвращает результат задачи из SDK. Сохраните ID задачи и используйте GET-маршрут для последующих проверок. Успешный POST не означает, что токен уже пригоден для использования.

Оба маршрута требуют ключ интеграции. Это доверенный внутренний интерфейс, а не авторизация отдельных пользователей: клиенты с этим ключом имеют общий доступ через настроенное рабочее пространство.

Получайте существующую задачу через GET до ее завершения

Отправьте GET /captcha/tasks/{id} с тем же заголовком ключа интеграции. Обработчик вызывает только GetTask; он никогда не создает задачу на замену. Он запрашивает ожидание до 15 секунд в контексте запроса на 25 секунд.

  • pending или solving: сохраните тот же ID задачи и запросите ее снова.
  • ready: прочитайте решение. Это единственный статус с пригодным для использования результатом.
  • failed: прекратите опрос и изучите errorCode и error. Устраните причину, прежде чем решать, создавать ли новую задачу.

Проверьте HTTP-статус ответа, прежде чем декодировать успешный результат задачи. В этом сервере неавторизованные запросы возвращают 401, некорректные входные данные задачи — 400, а ошибки запросов SDK — 502. Возвращенная задача со статусом failed — это другой исход, не ошибка HTTP-запроса.

Восстановите задачу после тайм-аута без нового решения

Тайм-аут не доказывает, что создание не удалось. Отмена контекста запроса прекращает локальное ожидание, а не удаленную задачу. SDK никогда автоматически не повторяет POST-запрос создания.

  1. 1.

    Если у вас есть ID задачи, запросите ее

    Используйте GET-маршрут с этим ID. При ошибках SDK JSON-ответ с ошибкой в примере содержит taskId и requestId, если SDK предоставляет их.

  2. 2.

    Если у вас есть только ID запроса, повторите исходный запрос создания

    Отправьте POST повторно с тем же X-Request-ID и неизменными входными данными задачи. Это означает, что настроенные имя хоста, действие и прокси должны остаться прежними. Тот же ID запроса и тот же запрос задачи восстанавливают существующую задачу; другие входные данные с этим ID приводят к конфликту.

  3. 3.

    Сохраните ID до первого запроса

    SDK генерирует ID запроса, если он не указан, но при разрыве соединения вызывающая сторона может его не получить. Если выбрать и сохранить X-Request-ID до POST, восстановление не будет зависеть от ответа с ошибкой.

Используйте готовый результат с тем же прокси

Этот сервер возвращает результат; SDK не отправляет его целевому сайту. Ваш код отправки должен использовать токен, возвращенные параметры браузера userAgent и secChUa, а также прокси, на котором решение удалось. В этом примере с одним прокси продолжайте использовать настроенный прокси, а не меняйте IP после решения.

Задача со статусом ready означает, что решение сгенерировано, а не что целевой сайт принял запрос вашего приложения. Если отправка не удалась, проверьте исходящие токен, параметры браузера, прокси и запрос к целевому сайту, прежде чем платить за новое решение.

Запустите первую задачу.

Начните с $5 на балансе рабочего пространства.

Создать рабочее пространство
Используйте Go SDK в сервере net/http · solvethree