استخدام حزمة SDK لـ Go في معالج Gin

بقلم solvethreeمدة القراءة: 4 دقيقة

استخدم عميل solvethree مشتركًا واحدًا ومرّر سياقًا فرعيًا من c.Request.Context() مقيّدًا بمهلة نهائية إلى Solve. احتفظ بإعدادات الهدف ومفتاح API على الخادم، وصادِق الجهة المستدعية للتطبيق قبل إنشاء مهمة.

في هذه الصفحة

ثبّت التبعيات واضبط الهدف

  1. 1.

    أنشئ وحدة Go وثبّت التبعيات

    استخدم Go 1.25 أو إصدارًا أحدث للإصدار الحالي من Gin. تتطلب حزمة solvethree SDK نفسها Go 1.22+. هيّئ وحدة تطبيقك باستخدام go mod init، مع مسار الوحدة الخاص بك. ثبّت Gin باتباع دليل البدء السريع الخاص به، ثم استخدم go get لإضافة solvethree.com/[email protected]. تُقدَّم حزمة SDK الرسمية عبر وكيل الوحدات العام المستضاف على النطاق؛ وتُقدَّم من solvethree.com.

  2. 2.

    اضبط بيانات اعتماد الخادم

    اضبط SOLVETHREE_API_KEY على مفتاح API لمساحة عملك، وINTEGRATION_KEY على السر الذي سيرسله تطبيقك الداخلي في X-Integration-Key. هاتان مجموعتان منفصلتان من بيانات الاعتماد: لا تحتاج الجهة المستدعية للتطبيق إلى مفتاح solvethree API.

  3. 3.

    اضبط الهدف الثابت

    اضبط CAPTCHA_SITE على اسم المضيف المستهدف وSOLVETHREE_PROXY على الوكيل المستخدم للحل. أنشئ ملف تعريف موقع نشطًا في مساحة العمل أولًا؛ راجع إعداد ملف تعريف الموقع. يثبّت المثال Action على login، لذا غيّر هذه القيمة إذا كان تكاملك يستخدم إجراءً آخر. ضبط اسم المضيف والإجراء لا ينشئ ملف تعريف.

أضف مسار Gin المحمي بالمصادقة

يُنشأ العميل مرة واحدة، وهو آمن للاستخدام مع الطلبات المتزامنة. يتحقّق المسار من بيانات اعتماد التطبيق الداخلي قبل استدعاء solvethree. يقبل معرّف طلب من الجهة المستدعية، لكنه لا يقبل هدفًا أو وكيلًا اعتباطيًا.

Gin · حل ضمن حدود باستخدام SDK الرسمي لـ Go
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"))
}

تحدّد المهمة Site وAction وProxy واحدًا. وتترك Type وURL دون تعيين، كما يتطلب reCAPTCHA، وتستخدم وضع Enterprise v3 الافتراضي.

تحدّ المهلة النهائية الصريحة للسياق من انتظار المعالج إلى 180 ثانية؛ وقد يؤدي انقطاع اتصال العميل إلى إلغائه قبل ذلك. يجب أن يسمح خادم HTTP وأي وكيل عكسي بهذه المدة للطلب. إذا لم يتمكنا من ذلك، فاستخدم عمليتي إنشاء واسترجاع منفصلتين بدلًا من إبقاء هذا المسار المتزامن مفتوحًا.

يرتبط المستمع بعنوان الاسترجاع المحلي. ادمج المسار مع إعدادات المصادقة الداخلية والنشر الحالية لتطبيقك؛ ولا تُتِح نقطة نهاية لحل مدفوع دون مصادقة الجهة المستدعية.

عالِج الأخطاء دون كشف الأسرار

يستخدم المعالج errors.As بدلًا من مطابقة نصوص الأخطاء. ينتج عن TaskFailedError نهائي استجابة 502 تحتوي على معرّف المهمة ورمز الخطأ. وتنتج أخطاء SDK المغلّفة الأخرى استجابة 502 تحتوي على معرّفات الاستعادة. يعيد المسار الاحتياطي رسالة 400 ثابتة بدلًا من كشف الأخطاء الخام أو بيانات الاعتماد أو عناوين URL للوكلاء.

لا تعني جميع استجابات 502 هذه أن عملية الحل فشلت. استخدم errors.Is لتمييز الإلغاء أو انتهاء المهلة. وللمعالجة الخاصة بـ HTTP، يمكن لـ errors.As استخراج APIError متداخل يتضمن StatusCode وRetryAfter. احتفظ بهذا التمييز في التشخيصات الداخلية بدلًا من اعتبار كل خطأ سببًا لإنشاء مهمة أخرى.

يجب عدم الاستعلام مجددًا عن مهمة انتهت بالفشل. استرجعها إذا احتجت إلى نص الخطأ، ثم صحّح السبب قبل بدء عملية حل أخرى. تُردّ تكلفة عمليات الحل الفاشلة.

احتفظ بالمعرّفات عند انتهاء مهلة الطلب

يوقف الإلغاء الانتظار، وليس العمل الجاري عن بُعد. يُرجع المثال معرّفات الاسترداد متى أمكن، لكنه لا يحفظها حفظًا دائمًا. إذا انقطع اتصال المستدعي، فقد لا تصل استجابة JSON هذه أبدًا.

  1. 1.

    عيّن معرّف الطلب قبل استدعاء المسار

    اجعل المستدعي الداخلي يحتفظ بقيمة X-Request-ID ثابتة لكل عملية حل منطقية. تتكون المعرّفات الصالحة من 1–64 من أحرف ASCII أو الأرقام أو الشرطات السفلية أو الواصلات. تُنشئ SDK معرّفًا عند غيابه، لكن تعيينه مسبقًا يتيح الاسترداد حتى في حال فقدان الاستجابة.

  2. 2.

    احتفظ بمدخلات المهمة كما هي تمامًا

    خزّن اسم المضيف والإجراء والوكيل ومعرّف الطلب في مساحة تخزين محمية للتطبيق. يجب ألا تؤدي إعادة المحاولة بعد تغيير إعدادات البيئة إلى استبدال مدخلات المهمة بمدخلات مختلفة دون تنبيه.

  3. 3.

    استعد المهمة قبل إنشاء عمل جديد

    إذا كان معرّف المهمة معروفًا، فاستدعِ GetTask باستخدام سياق جديد بمهلة محدودة. وإن لم يكن معروفًا، فأعد إرسال المهمة الأصلية عبر CreateTask باستخدام معرّف الطلب والمدخلات نفسها. يُرجع ذلك المهمة الموجودة؛ أما استخدام مدخلات مختلفة مع المعرّف نفسه فيؤدي إلى تعارض. واصل الاسترجاع فقط ما دامت المهمة قيد الانتظار أو قيد الحل.

تُنشئ Solve المهمة مرة واحدة، ولا تعيد المحاولة إلا لاستجابات الاستعلام المؤقتة ذات حالات HTTP ‏429 أو 502 أو 503 أو 504، مع مراعاة Retry-After ضمن مهلة السياق. لا تعيد CreateTask محاولة POST تلقائيًا مطلقًا، لذا يظل انتهاء مهلة الإنشاء بحاجة إلى استرداد، لا إلى معرّف طلب جديد.

أرسل الرمز مع الهوية المُرجعة معه

تحتوي استجابة المعالج الناجحة على بيانات حل خاصة لمستدعي التطبيق المخوّل. استخدم Solution.Token، لا معرّف المهمة، في الطلب الموجّه إلى الهدف. استخدم UserAgent وSecChUA المُرجعين، واحصل على الوكيل الناجح باستخدام SuccessfulProxy(originalTask, readyResult).

لا تُرسل SDK أي شيء إلى الهدف. تعني المهمة الجاهزة أنه تم توليد حل، لا أن الموقع قبله. تحقّق من استجابة الهدف على نحو منفصل.

شغّل مهمتك الأولى.

ابدأ برصيد قدره $5 في مساحة العمل.

إنشاء مساحة عمل
استخدام حزمة SDK لـ Go في معالج Gin · solvethree