يقوم تكوين CaptchaAI في الإنتاج على قاعدة واحدة: افصل الإعدادات عن الكود، وحمّلها من ثلاث طبقات مرتّبة — متغيرات البيئة، ثم ملف التكوين، ثم القيم الافتراضية داخل الكود. بهذا الترتيب تُغيّر التزامن أو المهلة أو مفتاح الـ API لبيئة بعينها دون أن تلمس سطرًا واحدًا من الكود أو تعيد النشر. أما تثبيت المفاتيح والمهلات داخل الكود مباشرةً فيصلح للنماذج الأولية فقط، ويتحوّل إلى عبء تشغيلي فور وصولك إلى بيئات متعددة وفريق يتشارك الأسرار.
ترتيب أولوية طبقات التكوين
Priority (highest → lowest):
1. Environment variables ← deployment-specific overrides
2. Config file (YAML/JSON) ← version-controlled defaults
3. Application defaults ← fallback values in code
القاعدة بسيطة: كلّما اقتربت الطبقة من مُشغّل الخدمة، ارتفعت أولويتها. تتجاوز متغيرات البيئة ما في ملف التكوين، ويتجاوز ملف التكوين القيم الافتراضية المدمجة في الكود. وإذا كانت خدمتك تدعم وسائط سطر الأوامر، فأضِفها كطبقة رابعة فوق متغيرات البيئة بالمنطق نفسه. وزّع القيم على الطبقات الثلاث بحسب حساسيتها وتكرار تغيّرها:
- متغيرات البيئة: مفتاح الـ API والأسرار وأي قيمة تختلف بين النشرات مثل التزامن أو الخادم الوسيط.
- ملف التكوين: القيم الافتراضية الآمنة المشتركة بين أعضاء الفريق والقابلة للحفظ في نظام التحكم بالمصادر.
- القيم الافتراضية في الكود: شبكة أمان أخيرة تُبقي الخدمة قابلة للتشغيل حتى دون أي إعداد خارجي.
تحميل التكوين برمجيًا
يقرأ المُحمِّل التالي الطبقات الثلاث بالترتيب الصحيح، ثم يتحقق من القيم قبل تشغيل الخدمة: يفشل مبكرًا إذا كان مفتاح الـ API غائبًا أو كانت قيم التزامن أو الاستطلاع خارج النطاق المسموح.
Python
import os
import yaml
from dataclasses import dataclass, field
from pathlib import Path
@dataclass
class CaptchaAIConfig:
api_key: str = ""
submit_url: str = "https://ocr.captchaai.com/in.php"
poll_url: str = "https://ocr.captchaai.com/res.php"
poll_interval: int = 5
max_polls: int = 60
concurrency: int = 10
timeout: int = 300
proxy: str = ""
callback_url: str = ""
retries: int = 3
log_level: str = "info"
@classmethod
def load(cls, config_path=None):
"""Load config: env vars override file, which overrides defaults."""
config = cls()
# Layer 2: Config file
if config_path and Path(config_path).exists():
with open(config_path) as f:
file_config = yaml.safe_load(f) or {}
for key, value in file_config.items():
if hasattr(config, key):
setattr(config, key, value)
# Layer 1: Environment variables (highest priority)
env_map = {
"CAPTCHAAI_API_KEY": "api_key",
"CAPTCHAAI_SUBMIT_URL": "submit_url",
"CAPTCHAAI_POLL_URL": "poll_url",
"CAPTCHAAI_POLL_INTERVAL": "poll_interval",
"CAPTCHAAI_MAX_POLLS": "max_polls",
"CAPTCHAAI_CONCURRENCY": "concurrency",
"CAPTCHAAI_TIMEOUT": "timeout",
"CAPTCHAAI_PROXY": "proxy",
"CAPTCHAAI_CALLBACK_URL": "callback_url",
"CAPTCHAAI_RETRIES": "retries",
"CAPTCHAAI_LOG_LEVEL": "log_level",
}
for env_key, attr_name in env_map.items():
value = os.environ.get(env_key)
if value is not None:
# Cast to correct type
current = getattr(config, attr_name)
if isinstance(current, int):
value = int(value)
setattr(config, attr_name, value)
config.validate()
return config
def validate(self):
if not self.api_key:
raise ValueError("CAPTCHAAI_API_KEY is required")
if self.poll_interval < 1:
raise ValueError("poll_interval must be >= 1")
if self.concurrency < 1:
raise ValueError("concurrency must be >= 1")
# Usage
config = CaptchaAIConfig.load("config/captchaai.yaml")
print(f"Concurrency: {config.concurrency}, Timeout: {config.timeout}s")
JavaScript
const fs = require("fs");
const yaml = require("js-yaml");
const path = require("path");
class CaptchaAIConfig {
static defaults = {
apiKey: "",
submitUrl: "https://ocr.captchaai.com/in.php",
pollUrl: "https://ocr.captchaai.com/res.php",
pollInterval: 5,
maxPolls: 60,
concurrency: 10,
timeout: 300,
proxy: "",
callbackUrl: "",
retries: 3,
logLevel: "info",
};
static envMap = {
CAPTCHAAI_API_KEY: "apiKey",
CAPTCHAAI_SUBMIT_URL: "submitUrl",
CAPTCHAAI_POLL_URL: "pollUrl",
CAPTCHAAI_POLL_INTERVAL: { key: "pollInterval", type: "int" },
CAPTCHAAI_MAX_POLLS: { key: "maxPolls", type: "int" },
CAPTCHAAI_CONCURRENCY: { key: "concurrency", type: "int" },
CAPTCHAAI_TIMEOUT: { key: "timeout", type: "int" },
CAPTCHAAI_PROXY: "proxy",
CAPTCHAAI_CALLBACK_URL: "callbackUrl",
CAPTCHAAI_RETRIES: { key: "retries", type: "int" },
CAPTCHAAI_LOG_LEVEL: "logLevel",
};
static load(configPath = null) {
let config = { ...CaptchaAIConfig.defaults };
// Layer 2: Config file
if (configPath && fs.existsSync(configPath)) {
const ext = path.extname(configPath);
const raw = fs.readFileSync(configPath, "utf8");
const fileConfig = ext === ".json" ? JSON.parse(raw) : yaml.load(raw);
config = { ...config, ...fileConfig };
}
// Layer 1: Environment variables
for (const [envKey, mapping] of Object.entries(CaptchaAIConfig.envMap)) {
const value = process.env[envKey];
if (value !== undefined) {
const attrKey = typeof mapping === "string" ? mapping : mapping.key;
const type = typeof mapping === "string" ? "string" : mapping.type;
config[attrKey] = type === "int" ? parseInt(value, 10) : value;
}
}
CaptchaAIConfig.validate(config);
return config;
}
static validate(config) {
if (!config.apiKey) throw new Error("CAPTCHAAI_API_KEY is required");
if (config.pollInterval < 1) throw new Error("pollInterval must be >= 1");
if (config.concurrency < 1) throw new Error("concurrency must be >= 1");
}
}
// Usage
const config = CaptchaAIConfig.load("config/captchaai.yaml");
console.log(`Concurrency: ${config.concurrency}, Timeout: ${config.timeout}s`);
المرجع الكامل لمعلمات التكوين
| المعلمة | متغير البيئة | القيمة الافتراضية | الوصف |
|---|---|---|---|
| مفتاح الـ API | CAPTCHAAI_API_KEY |
— | مطلوب. مفتاح CaptchaAI API الخاص بك |
| رابط الإرسال | CAPTCHAAI_SUBMIT_URL |
https://ocr.captchaai.com/in.php |
نقطة نهاية إرسال المهمة |
| رابط الاستطلاع | CAPTCHAAI_POLL_URL |
https://ocr.captchaai.com/res.php |
نقطة نهاية استطلاع النتيجة |
| فاصل الاستطلاع | CAPTCHAAI_POLL_INTERVAL |
5 |
الثواني بين محاولات الاستطلاع |
| أقصى عدد لمحاولات الاستطلاع | CAPTCHAAI_MAX_POLLS |
60 |
الحد الأقصى للمحاولات قبل انتهاء المهلة |
| التزامن | CAPTCHAAI_CONCURRENCY |
10 |
أقصى عدد لمهام CAPTCHA المتوازية |
| المهلة | CAPTCHAAI_TIMEOUT |
300 |
المهلة الإجمالية بالثواني |
| الخادم الوسيط | CAPTCHAAI_PROXY |
— | رابط الخادم الوسيط لحل اختبار CAPTCHA |
| رابط رد النداء | CAPTCHAAI_CALLBACK_URL |
— | رابط الـ Webhook للنتائج غير المتزامنة |
| إعادة المحاولة | CAPTCHAAI_RETRIES |
3 |
إعادة المحاولة عند حالات الفشل العابرة |
| مستوى السجل | CAPTCHAAI_LOG_LEVEL |
info |
مستوى تفصيل التسجيل |
ملفات تكوين منفصلة لكل بيئة
احتفظ بملف أساسي واحد يضم القيم الآمنة المشتركة، ثم أضِف ملفًا لكل بيئة يتجاوز ما يلزم فقط. لاحظ أن مفتاح الـ API يبقى فارغًا في كل هذه الملفات ويُضبط دائمًا عبر متغير بيئة.
# config/captchaai.yaml — base
api_key: "" # Always set via env var
concurrency: 5
poll_interval: 5
retries: 3
log_level: info
# config/captchaai.production.yaml
concurrency: 20
poll_interval: 3
timeout: 180
log_level: warning
# config/captchaai.staging.yaml
concurrency: 3
poll_interval: 5
timeout: 300
log_level: debug
سيناريو عملي: مطابقة التزامن مع عدد الـ Threads
تخيّل فريقًا في الرياض يشغّل خط استخراج بيانات ليليًا يعتمد على CaptchaAI. اشترك الفريق في خطة ADVANCE بسعر 90 دولارًا شهريًا وتمنحه 50 خيط معالجة (Thread) مع عدد حلول غير محدود لكل خيط. القاعدة هنا مباشرة: لا تضبط CAPTCHAAI_CONCURRENCY بقيمة تتجاوز عدد الـ Threads المتاح في خطتك. فبقيمة تزامن قدرها 20 في الإنتاج، يبقى للفريق هامش واسع ضمن حدّ الخطة، بينما تُخفَّض القيمة إلى 3 في بيئة الاختبار كي لا تستهلك الخيوط المخصّصة للعمل الفعلي. ولأن الفوترة قائمة على الخيوط لا على عدد الحلول، فإن ضبط التزامن بذكاء يمنحك أقصى إنتاجية دون أي رسوم إضافية لكل عملية حل.
إدارة الأسرار ومفاتيح الـ API
لا تخزّن مفاتيح الـ API إطلاقًا داخل ملفات التكوين أو نظام التحكم بالمصادر، والتزم بثلاث قواعد أساسية:
- احقن المفتاح كمتغير بيئة عند التشغيل، لا داخل صورة الحاوية أو المستودع.
- امنح كل بيئة مفتاحًا مستقلًا يسهل إبطاله وتدويره دون التأثير على البيئات الأخرى.
- أخفِ المفتاح من السجلات ومخرجات التصحيح كي لا يتسرّب عبر لقطات الأخطاء.
| الطريقة | الأنسب لـ | مثال |
|---|---|---|
| متغيرات البيئة | الحاويات وأنظمة CI/CD | export CAPTCHAAI_API_KEY=abc123 |
| AWS Secrets Manager | البنية التحتية على AWS | جلب المفتاح عند بدء التشغيل مع تدوير تلقائي |
| HashiCorp Vault | البيئات متعددة السحابة والاستضافة الداخلية | أسرار ديناميكية بعمر محدد (TTL) |
| Docker Secrets | Docker Swarm / Compose | تُثبَّت على المسار /run/secrets/ |
ملف .env (للتطوير المحلي فقط) |
التطوير على جهاز المطوّر | مكتبة dotenv مع إضافته إلى .gitignore |
مثال Docker Compose
services:
captcha-worker:
image: captcha-worker:latest
environment:
- CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
- CAPTCHAAI_CONCURRENCY=15
- CAPTCHAAI_LOG_LEVEL=warning
env_file:
- .env.production
مفاتيح تبديل الميزات دون إعادة نشر
استخدم مفاتيح التبديل (Feature Flags) لتفعيل القدرات أو تعطيلها من متغيرات البيئة دون إعادة بناء الخدمة أو نشرها من جديد:
class FeatureFlags:
def __init__(self):
self.flags = {
"use_callback": os.environ.get("FF_USE_CALLBACK", "false") == "true",
"enable_proxy": os.environ.get("FF_ENABLE_PROXY", "true") == "true",
"max_concurrent": int(os.environ.get("FF_MAX_CONCURRENT", "10")),
}
def is_enabled(self, flag):
return self.flags.get(flag, False)
def get(self, flag, default=None):
return self.flags.get(flag, default)
الأسئلة الشائعة
كيف أضبط قيمة CAPTCHAAI_CONCURRENCY بما يناسب خطتي؟
اجعل قيمة التزامن مساوية لعدد الـ Threads في خطتك أو أقل منه. مثلًا خطة ADVANCE ($90 شهريًا، 50 خيطًا) تحتمل تزامنًا حتى 50 مهمة متوازية. وبما أن كل خطة تشمل حلولًا غير محدودة لكل خيط، فإن الحدّ الفعلي على إنتاجيتك هو عدد الخيوط وسرعة الحل لكل نوع، لا عدد العمليات.
أين أخزّن مفتاح الـ API في خطوط CI/CD بأمان؟
استخدم مخزن الأسرار المدمج في منصتك — مثل الأسرار المشفّرة في GitHub — وحقنه كمتغير بيئة عند التشغيل فقط. لا تكتب المفتاح داخل ملف التكوين أو سجلات البناء، ووجّه الخدمات المؤتمتة إلى AWS Secrets Manager أو HashiCorp Vault لجلبه لحظة بدء التشغيل.
لماذا تنجح بيئة الاختبار وتفشل بيئة الإنتاج؟
غالبًا لأن تجاوز البيئة الخاص بالإنتاج لم يُحمَّل، فتعمل الخدمة بقيم الاختبار. تأكد من ترتيب أولوية الطبقات، وأن ملف captchaai.production.yaml أو متغيرات البيئة المناسبة مضبوطة فعلًا، وأن سياق الخادم الوسيط والرؤوس مطابق لما نجح في الاختبار.
هل يمكنني تغيير الإعدادات دون إعادة النشر؟
نعم. اقرأ الإعدادات من متغيرات البيئة أو من خدمة تكوين مركزية مع كل دفعة مهام، لا عند بدء التشغيل فقط. عندها يكفي تحديث المتغير وإرسال إشارة إعادة تحميل لتطبيق القيمة الجديدة فورًا دون إيقاف الخدمة.
معالجة المشكلات الشائعة
| المشكلة | السبب المحتمل | الحل |
|---|---|---|
| مفتاح الـ API لا يُحمَّل | متغير البيئة غير مضبوط أو الاسم مكتوب خطأً | تحقق من echo $CAPTCHAAI_API_KEY وراجع تهجئة الاسم |
| ملف التكوين يُتجاهَل | المسار خاطئ أو مكتبة YAML غير مثبّتة | تأكد من وجود الملف وثبّت pyyaml أو js-yaml |
| الإنتاج يعمل بإعدادات التطوير | تجاوز البيئة الخاص لم يُطبَّق | راجع أولوية المتغيرات وقيمة APP_ENV أو NODE_ENV |
| ظهور المفتاح داخل السجلات | طباعة التكوين تتضمن مفتاح الـ API | أخفِ الحقول الحساسة في مخرجات السجل |
الخطوات التالية
- ابدأ سريعًا وحلّ أول كابتشا خلال 5 دقائق
- حلّ reCAPTCHA v2 عبر الـ API خطوة بخطوة
- التعامل مع Cloudflare Turnstile عبر الـ API
- حلّ GeeTest v3 عبر الـ API