WebSocket ليست طلب HTTP عادي. بعد "مصافحة" (handshake) الأولية، يبقى الاتصال مفتوحًا، وتدفق البيانات يحدث في كلا الاتجاهين بشكل مستمر. لهذا السبب، غالبًا ما تقطع البروكسي HTTP القياسية اتصالات WS أو لا تستطيع معالجتها على الإطلاق. في هذه المقالة، سنستعرض كيفية بروكسي حركة مرور WebSocket بشكل صحيح: ما هي البروكسي المناسبة، وكيفية إعدادها، وما هي الأخطاء الأكثر شيوعًا.
كيف يعمل WebSocket ولماذا هو معقد للبروكسي
لفهم المشكلة، يجب أن نفهم الميكانيكا. يبدأ اتصال WebSocket كطلب HTTP عادي - يرسل العميل رأس Upgrade: websocket وConnection: Upgrade. يستجيب الخادم برمز 101 Switching Protocols - ومنذ تلك اللحظة، يتوقف الاتصال عن كونه HTTP. يتحول إلى قناة ثنائية الاتجاه دائمة، حيث تتدفق البيانات في إطارات.
يواجه بروكسي HTTP/1.1 القياسي، الذي يعرف فقط كيفية تمرير الطلبات والاستجابات، مشكلة: لا يعرف ماذا يفعل بالاتصال بعد الاستجابة 101. العديد من خوادم البروكسي تغلق الاتصال في هذه اللحظة أو تعيد خطأ 502 Bad Gateway. البعض الآخر يحتفظ بالاتصال، لكنه لا يعرف كيفية تمرير إطارات WebSocket بشكل صحيح، مما يؤدي إلى انقطاع أو تشويه البيانات.
إليك الاختلافات الرئيسية بين WebSocket وHTTP العادي من منظور البروكسي:
| المعلمة | HTTP | WebSocket |
|---|---|---|
| نوع الاتصال | طلب → استجابة → إغلاق | دائم، ثنائي الاتجاه |
| مدة الحياة | ثوانٍ (طلب واحد) | دقائق، ساعات، أيام |
| مبادر البيانات | فقط العميل | العميل والخادم |
| البروتوكول بعد المصافحة | HTTP | خاص (RFC 6455) |
| المنافذ | 80، 443 | 80 (WS)، 443 (WSS) |
بسبب تغيير البروتوكول بعد المصافحة، لا تستطيع معظم حلول البروكسي البسيطة التعامل مع WebSocket. يجب إما استخدام بروكسي يدعم صراحة التوصيل، أو استخدام SOCKS5 - بروتوكول يعمل على مستوى أدنى ولا يفحص محتوى الحركة.
ما هي أنواع البروكسي التي تدعم WebSocket
ليست جميع البروكسي مفيدة بنفس القدر لـ WebSocket. دعونا نستعرض كل نوع:
| نوع البروكسي | دعم WS | آلية | تعقيد |
|---|---|---|---|
| بروكسي HTTP | ⚠️ جزئيًا | عبر نفق CONNECT | متوسط |
| بروكسي HTTPS | ✅ نعم | CONNECT + TLS | متوسط |
| SOCKS4 | ⚠️ محدود | نفق TCP بدون مصادقة | منخفضة |
| SOCKS5 | ✅ كاملة | TCP/UDP شفاف | منخفضة |
| بروكسي شفاف | ❌ لا | فقط HTTP | — |
الاستنتاج: الخيار الأمثل لمهام WebSocket هو SOCKS5. يعمل هذا البروتوكول على مستوى النقل ويقوم ببساطة بتوصيل اتصال TCP دون التعمق في محتوى الحركة. لا يهمه ما إذا كان داخل HTTP أو WebSocket أو SSH أو أي شيء آخر. يمكن أن تعمل بروكسي HTTP أيضًا مع WS، ولكن فقط عبر طريقة CONNECT - وهناك تفاصيل سنستعرضها أدناه.
طريقة CONNECT: كيف يقوم بروكسي HTTP بتوصيل WebSocket
طريقة HTTP CONNECT هي آلية خاصة تتيح لبروكسي HTTP إنشاء نفق "أعمى" إلى الخادم المستهدف. لا يقوم البروكسي بتحليل الحركة داخل النفق، بل يقوم ببساطة بإعادة توجيه البايتات. هكذا يعمل HTTPS عبر بروكسي HTTP - وهكذا يمكن بروكسي WebSocket.
تبدو العملية كما يلي:
- يرسل العميل طلبًا للبروكسي:
CONNECT example.com:443 HTTP/1.1 - يقوم البروكسي بإنشاء اتصال TCP مع
example.com:443 - يستجيب البروكسي للعميل:
200 Connection Established - من هذه اللحظة، يقوم البروكسي ببساطة بنقل البايتات ذهابًا وإيابًا - دون تحليلها
- ينفذ العميل TLS-handshake مباشرة مع الخادم عبر النفق
- ثم - WebSocket-handshake فوق TLS
القيد الرئيسي: عادةً ما يُسمح بطريقة CONNECT فقط على المنفذ 443. إذا كان خادم WebSocket الخاص بك يعمل على منفذ غير قياسي (مثل 8080 أو 9000)، قد يرفض البروكسي الاتصال. في هذه الحالة، يُفضل SOCKS5 - فهو ليس لديه قيود على المنافذ.
من المهم أيضًا مراعاة أن بعض بروكسي HTTP المؤسسية (مثل Squid في التكوين القياسي) تحظر صراحةً طريقة CONNECT لبعض المنافذ أو تتطلب مصادقة. إذا كنت تعمل مع مزودي بروكسي تجاريين، فإن معظمهم يدعمون CONNECT دون قيود.
# مثال على طلب CONNECT عبر curl (للتحقق)
curl -v -x http://proxy_host:proxy_port \
--proxytunnel \
https://echo.websocket.org
# إذا كان البروكسي يدعم CONNECT - سترى:
# * CONNECT tunnel established, response 200
SOCKS5 وWebSocket: لماذا هو الخيار الأفضل
SOCKS5 هو بروتوكول بروكسي على مستوى اتصالات TCP/UDP. على عكس بروكسي HTTP، لا يعرف SOCKS5 أي شيء عن البروتوكول التطبيقي الذي يسير داخله. إنه ببساطة ينشئ نفقًا بين العميل والخادم المستهدف، وهذا كل شيء. يجعل هذا منه مثاليًا لـ WebSocket لعدة أسباب:
- لا توجد قيود على البروتوكول: SOCKS5 ينقل أي حركة TCP، بما في ذلك WS، WSS، SSH، FTP، إلخ.
- لا توجد قيود على المنافذ: يعمل مع أي منفذ، وليس فقط 443 أو 80
- لا يوجد انقطاع عند تغيير البروتوكول: البروكسي لا "ترى" الانتقال من HTTP إلى WebSocket
- دعم المصادقة: يدعم SOCKS5 تسجيل الدخول/كلمة المرور، مما يجعله مناسبًا للبروكسي التجارية
- دعم UDP: إذا كانت تطبيقك يستخدم WebRTC أو UDP بجانب WS - فإن SOCKS5 سيتعامل مع ذلك
تدعم جميع المكتبات الحديثة تقريبًا للعمل مع WebSocket SOCKS5 إما مباشرة أو من خلال حزم إضافية. أدناه سنستعرض أمثلة محددة لـ Python وNode.js.
💡 متى تختار SOCKS5 ومتى تختار HTTP CONNECT؟
استخدم SOCKS5 إذا: كان لديك منفذ غير قياسي، تحتاج إلى دعم UDP، تريد الحد الأدنى من الإعدادات.
استخدم HTTP CONNECT إذا: كان مزود البروكسي لا يدعم SOCKS5، أو كنت تعمل عبر بروكسي مؤسسي.
أمثلة على التعليمات البرمجية: WebSocket عبر البروكسي بلغة Python
دعونا نستعرض بعض السيناريوهات لـ Python. المكتبات الأكثر شعبية لـ WebSocket في Python هي websockets وwebsocket-client.
الخيار 1: websocket-client عبر بروكسي HTTP
import websocket
# إعدادات بروكسي HTTP
proxy_host = "proxy.example.com"
proxy_port = 8080
proxy_user = "username"
proxy_pass = "password"
ws = websocket.WebSocket()
ws.connect(
"wss://echo.websocket.org",
http_proxy_host=proxy_host,
http_proxy_port=proxy_port,
http_proxy_auth=(proxy_user, proxy_pass),
proxy_type="http" # أو "socks5"
)
ws.send("مرحبًا، WebSocket!")
result = ws.recv()
print(f"تم الاستلام: {result}")
ws.close()
الخيار 2: websocket-client عبر SOCKS5
import websocket
# يحتاج SOCKS5 إلى حزمة: pip install PySocks
ws = websocket.WebSocket()
ws.connect(
"wss://echo.websocket.org",
http_proxy_host="socks5_proxy.example.com",
http_proxy_port=1080,
http_proxy_auth=("username", "password"),
proxy_type="socks5"
)
ws.send("رسالة اختبار")
print(ws.recv())
ws.close()
الخيار 3: مكتبة websockets (asyncio) عبر SOCKS5
مكتبة websockets (asyncio) لا تدعم البروكسي بشكل مدمج، لذا نستخدم python-socks لإنشاء نفق:
# pip install websockets python-socks[asyncio]
import asyncio
import websockets
from python_socks.async_.asyncio import Proxy
async def connect_via_socks5():
proxy = Proxy.from_url("socks5://username:[email protected]:1080")
# إنشاء اتصال TCP عبر البروكسي
sock = await proxy.connect(
dest_host="echo.websocket.org",
dest_port=443
)
# تمرير المقبس إلى websockets
async with websockets.connect(
"wss://echo.websocket.org",
sock=sock
) as ws:
await ws.send("مرحبًا عبر SOCKS5!")
response = await ws.recv()
print(f"الرد: {response}")
asyncio.run(connect_via_socks5())
الخيار 4: تصحيح عالمي عبر PySocks
إذا كنت ترغب في توجيه كل حركة مرور تطبيق Python عبر SOCKS5 دون تغيير كل استدعاء - استخدم socks.setdefaultproxy():
# pip install PySocks
import socks
import socket
import websocket
# تصحيح المقبس عالميًا
socks.set_default_proxy(
socks.SOCKS5,
"proxy.example.com",
1080,
username="user",
password="pass"
)
socket.socket = socks.socksocket
# الآن جميع الاتصالات تمر عبر SOCKS5
ws = websocket.WebSocket()
ws.connect("wss://echo.websocket.org")
ws.send("بروكسي SOCKS5 عالمي!")
print(ws.recv())
ws.close()
أمثلة على التعليمات البرمجية: WebSocket عبر البروكسي على Node.js
في نظام Node.js البيئي، المكتبة الأكثر شعبية لـ WebSocket هي ws. لاستخدام البروكسي عبر HTTP/SOCKS5، يتم استخدام حزمة https-proxy-agent أو socks-proxy-agent.
الخيار 1: WSS عبر بروكسي HTTP CONNECT
// npm install ws https-proxy-agent
const WebSocket = require('ws');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxyUrl = 'http://username:[email protected]:8080';
const agent = new HttpsProxyAgent(proxyUrl);
const ws = new WebSocket('wss://echo.websocket.org', { agent });
ws.on('open', () => {
console.log('تم إنشاء الاتصال عبر بروكسي HTTP');
ws.send('مرحبًا من Node.js!');
});
ws.on('message', (data) => {
console.log(`تم الاستلام: ${data}`);
ws.close();
});
ws.on('error', (err) => {
console.error('خطأ:', err.message);
});
الخيار 2: WSS عبر SOCKS5
// npm install ws socks-proxy-agent
const WebSocket = require('ws');
const { SocksProxyAgent } = require('socks-proxy-agent');
const proxyUrl = 'socks5://username:[email protected]:1080';
const agent = new SocksProxyAgent(proxyUrl);
const ws = new WebSocket('wss://echo.websocket.org', { agent });
ws.on('open', () => {
console.log('تم إنشاء الاتصال عبر SOCKS5');
ws.send(JSON.stringify({ type: 'ping', data: 'test' }));
});
ws.on('message', (data) => {
console.log('الرد:', data.toString());
});
ws.on('close', (code, reason) => {
console.log(`تم الإغلاق: ${code} - ${reason}`);
});
الخيار 3: WS (بدون TLS) عبر بروكسي HTTP يدويًا
لتوصيل WS غير المشفر (المنفذ 80) عبر بروكسي HTTP، يجب إرسال طلب CONNECT يدويًا، حيث تعمل الوكلاء القياسية غالبًا فقط مع HTTPS:
const net = require('net');
const WebSocket = require('ws');
function createTunnel(proxyHost, proxyPort, targetHost, targetPort) {
return new Promise((resolve, reject) => {
const socket = net.connect(proxyPort, proxyHost, () => {
const connectReq =
`CONNECT ${targetHost}:${targetPort} HTTP/1.1\r\n` +
`Host: ${targetHost}:${targetPort}\r\n` +
`Proxy-Authorization: Basic ${Buffer.from('user:pass').toString('base64')}\r\n` +
`\r\n`;
socket.write(connectReq);
});
socket.once('data', (data) => {
if (data.toString().includes('200')) {
resolve(socket);
} else {
reject(new Error(`رفض البروكسي CONNECT: ${data.toString()}`));
}
});
socket.on('error', reject);
});
}
async function main() {
const socket = await createTunnel(
'proxy.example.com', 8080,
'echo.websocket.org', 80
);
const ws = new WebSocket('ws://echo.websocket.org', { socket });
ws.on('open', () => {
ws.send('نفق CONNECT يدوي!');
});
ws.on('message', (data) => {
console.log('تم الاستلام:', data.toString());
ws.close();
});
}
main().catch(console.error);
WSS (WebSocket Secure): ميزات البروكسي مع TLS
WSS هو WebSocket فوق TLS (مماثل لـ HTTPS لـ HTTP). عند بروكسي WSS عبر SOCKS5 أو HTTP CONNECT، هناك نقطة مهمة: تشفير TLS يتم إنشاؤه بين العميل والخادم النهائي، وليس بين العميل والبروكسي. وهذا يعني:
- خادم البروكسي لا يرى محتوى حركة WSS - فقط عنوان IP ورقم المنفذ الهدف
- يتم التحقق من شهادة الخادم من قبل العميل مباشرة
- لا يمكن للبروكسي "استبدال" أو "اعتراض" البيانات دون تثبيت شهادة CA خاصة به
هذه أخبار جيدة من منظور الأمان. ولكن هناك أيضًا تفاصيل عملية عند الإعداد:
التحقق من الشهادة عبر البروكسي
أحيانًا عند استخدام البروكسي المؤسسية (التي تقوم بفحص SSL)، قد تحصل على خطأ في التحقق من الشهادة. في هذه الحالة، يقوم البروكسي باستبدال شهادة الخادم بشهادته الخاصة. للعمل في مثل هذا البيئة، يجب إضافة شهادة CA للبروكسي إلى الموثوق بها:
# Python: تمرير شهادة CA للبروكسي المؤسسي
import ssl
import websocket
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations("/path/to/corporate-ca.crt")
ws = websocket.WebSocket(sslopt={"context": ssl_context})
ws.connect(
"wss://internal.example.com",
http_proxy_host="corp-proxy.company.com",
http_proxy_port=8080,
proxy_type="http"
)
# في البيئات التجريبية (ليس للإنتاج!) يمكن تعطيل التحقق:
ws_test = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
ws_test.connect("wss://test.example.com", http_proxy_host="proxy", http_proxy_port=8080)
⚠️ مهم
تعطيل التحقق من شهادة TLS (CERT_NONE) مقبول فقط في البيئة التجريبية. في الإنتاج، هذا يخلق ثغرة أمنية لهجمات من نوع MITM (man-in-the-middle).
SNI (Server Name Indication) عبر البروكسي
عند استخدام SOCKS5، يمكن للعميل حل DNS بنفسه أو تفويض ذلك للبروكسي. وضع socks5h (SOCKS5 مع حل اسم المضيف) يعني أن طلب DNS يتم على جانب خادم البروكسي. هذا مهم لـ WSS، حيث يجب أن يتطابق رأس SNI في TLS-handshake مع اسم المضيف:
# socks5 — يتم حل DNS محليًا (بواسطة العميل)
# socks5h — يتم حل DNS بواسطة خادم البروكسي (موصى به للخصوصية)
from python_socks.async_.asyncio import Proxy
# DNS عبر البروكسي (موصى به):
proxy = Proxy.from_url("socks5h://user:[email protected]:1080")
# DNS محليًا:
proxy = Proxy.from_url("socks5://user:[email protected]:1080")
الأخطاء الشائعة وكيفية إصلاحها
جمعنا أكثر المشاكل شيوعًا عند بروكسي WebSocket مع الحلول:
الخطأ 1: 407 Proxy Authentication Required
يتطلب البروكسي المصادقة، لكنك لم تمرر بيانات الاعتماد أو مررتها بشكل غير صحيح.
# ❌ غير صحيح - لا توجد مصادقة
ws.connect("wss://example.com", http_proxy_host="proxy.example.com", http_proxy_port=8080)
# ✅ صحيح - تمرير اسم المستخدم وكلمة المرور
ws.connect(
"wss://example.com",
http_proxy_host="proxy.example.com",
http_proxy_port=8080,
http_proxy_auth=("username", "password")
)
الخطأ 2: Connection reset by peer / 502 Bad Gateway
لا يدعم البروكسي WebSocket أو طريقة CONNECT. الحل: انتقل إلى SOCKS5 أو تحقق مما إذا كان مزودك يدعم حركة WebSocket.
الخطأ 3: يتم قطع الاتصال بعد 30-60 ثانية
العديد من خوادم البروكسي تغلق الاتصالات TCP "غير النشطة" بسبب انتهاء المهلة. قد يبدو اتصال WebSocket غير نشط إذا لم يكن هناك تبادل بيانات. الحل هو تفعيل ping/pong:
# Python - تفعيل ping keepalive كل 20 ثانية
import websocket
import threading
def run():
ws = websocket.WebSocketApp(
"wss://echo.websocket.org",
on_message=lambda ws, msg: print(msg),
on_error=lambda ws, err: print(f"خطأ: {err}"),
on_close=lambda ws, c, m: print("تم الإغلاق")
)
ws.run_forever(
ping_interval=20, # إرسال ping كل 20 ثانية
ping_timeout=10, # الانتظار لـ pong لمدة لا تزيد عن 10 ثوان
http_proxy_host="proxy.example.com",
http_proxy_port=8080,
proxy_type="socks5"
)
thread = threading.Thread(target=run)
thread.start()
الخطأ 4: SSL: CERTIFICATE_VERIFY_FAILED
يحدث غالبًا عند استخدام بروكسي مؤسسي مع فحص SSL. الحل: أضف شهادة CA للبروكسي إلى الموثوق بها (انظر القسم أعلاه) أو استخدم SOCKS5 بدلاً من بروكسي HTTP - SOCKS5 لا يقوم بفحص SSL.
الخطأ 5: Handshake status 403 Forbidden
يقوم الخادم المستهدف بحظر الاتصال. الأسباب: تم إدراج عنوان IP للبروكسي في القائمة السوداء، أو تفتقر إلى الرؤوس المطلوبة (Origin، User-Agent)، أو يقوم الخادم بحظر الحركة من مراكز البيانات. الحل: استخدم بروكسي سكنية مع عناوين IP حقيقية لمستخدمي المنازل - من الصعب جدًا حظرها.
الخطأ 6: [Errno 111] Connection refused
خادم البروكسي غير متاح: عنوان/منفذ غير صحيح، أو البروكسي غير قيد التشغيل. تحقق من بيانات الاتصال وتوافر البروكسي من خلال طلب HTTP بسيط قبل اختبار WebSocket.
أي نوع من البروكسي يجب اختياره لمهام WebSocket
يعتمد اختيار نوع البروكسي على المهمة المحددة. إليك دليل عملي:
| المهمة | نوع موصى به | لماذا |
|---|---|---|
| التحليل عبر WS (البورصات، البيانات المالية) | بروكسي مراكز البيانات | سرعة عالية، تأخير منخفض، اتصال مستقر |
| تجاوز حظر خدمات WebSocket | بروكسي سكنية | عناوين IP حقيقية، خطر منخفض للحظر |
| تطبيقات الهاتف المحمول مع WS (العمل مع واجهات برمجة التطبيقات المحمولة) | بروكسي محمولة | عناوين IP لمشغلي الهواتف المحمولة - ثقة عالية من الخدمات |
| اختبار تحميل خادم WS | بروكسي مراكز البيانات | رخيص، سريع، العديد من الاتصالات المتزامنة |
| اختبار الجغرافيا لـ WS | بروكسي سكنية | مجموعة كبيرة من البلدان والمدن |
معلمات البروكسي المهمة لـ WebSocket
عند اختيار مزود البروكسي لمهام WebSocket، انتبه إلى المعلمات التالية:
- دعم SOCKS5: تأكد من أن المزود يقدم SOCKS5، وليس فقط HTTP
- مدة الجلسة (session duration): بالنسبة لـ WebSocket، تعتبر الجلسات "المثبّتة" مهمة - عنوان IP واحد لفترة طويلة. ستقطع البروكسي المتغيرة الاتصال
- مهلة الاتصال: يجب أن يدعم البروكسي اتصالات TCP طويلة الأمد (من عدة دقائق إلى ساعات)
- عرض النطاق الترددي: بالنسبة لـ WebSocket المتدفق (الفيديو، بيانات البورصة)، يعتبر عرض النطاق الترددي العالي بدون قيود مهمًا
- التأخير (latency): بالنسبة للتطبيقات المالية وروبوتات التداول، يعتبر الحد الأدنى من التأخير أمرًا حاسمًا - اختر بروكسي مع خوادم أقرب إلى الخدمة المستهدفة
💡 تحقق من دعم WebSocket من قبل مزود البروكسي
قبل شراء البروكسي لمهام WebSocket، اختبرها عبر خادم صدى مجاني:
wss://echo.websocket.org أو
wss://ws.postman-echo.com/raw.
إذا تم إنشاء الاتصال وتم إرجاع الرسائل - فإن البروكسي يعمل بشكل صحيح مع WebSocket.
إعداد الجلسة المثبتة لـ WebSocket
تستخدم معظم مزودي البروكسي السكنية تغيير IP بشكل افتراضي. بالنسبة لـ WebSocket، فإن هذا غير مقبول - كل تغيير في IP يعني قطع الاتصال. تأكد من أنك تستخدم وضع الجلسة المثبتة (IP ثابت). عادةً ما يتم ذلك من خلال تنسيق URL خاص للبروكسي:
# مثال على تنسيق الجلسة المثبتة (يعتمد على المزود):
# متغير (غير مناسب لـ WebSocket):
socks5://user:[email protected]:1080
# جلسة مثبتة (مناسبة لـ WebSocket):
socks5://user-session-abc123:[email protected]:1080
# أو عبر معلمة الدولة والجلسة:
socks5://user-country-us-session-12345:[email protected]:1080
الخاتمة
WebSocket ليست مجرد "HTTP مع اتصال طويل". إنها بروتوكول منفصل يتطلب نهجًا خاصًا عند البروكسي. الاستنتاجات الرئيسية من هذه المقالة:
- SOCKS5 - الخيار الأمثل لـ WebSocket: يعمل على مستوى النقل، لا يفحص البروتوكول، يدعم أي منافذ
- بروكسي HTTP عبر CONNECT يعمل أيضًا، ولكن مع قيود على المنافذ ومشاكل محتملة مع فحص SSL
- الجلسات المثبتة ضرورية: ستقطع البروكسي المتغيرة اتصال WebSocket مع كل تغيير في IP
- Ping/pong keepalive ضروري لمنع قطع الاتصال بسبب انتهاء مهلة البروكسي
- WSS عبر البروكسي آمن: يتم إنشاء تشفير TLS مباشرة بين العميل والخادم، ولا يرى البروكسي المحتوى
إذا كنت تقوم بتطوير تطبيق يعمل مع WebSocket عبر البروكسي - ابدأ بـ SOCKS5 والجلسات المثبتة. سيوفر لك ذلك ساعات من تصحيح الأخطاء. لمهام حيث تكون السرعة العالية واستقرار الاتصال مهمين (روبوتات التداول، تدفق البيانات)، فإن بروكسي مراكز البيانات ذات التأخير المنخفض ستكون مثالية. إذا كان الخادم المستهدف يحظر بنشاط عناوين IP لمراكز البيانات - فكر في بروكسي سكنية: لديهم عناوين IP حقيقية لمستخدمي المنازل ومن الصعب جدًا حظرها حتى مع جلسات WebSocket الطويلة.
```