OkHttp هو عميل HTTP عالي الأداء لنظامي Android وKotlin، طورته شركة Square كأساس لـ Retrofit ومكتبات الشبكات الأخرى. يوفر إدارة فعالة للاتصالات، وتخزيناً مؤقتاً مدمجاً، ودعماً لـ HTTP/2. وفقاً لـ Square، 2025، OkHttp يعالج مليارات الطلبات يومياً في التطبيقات حول العالم.
الخلاصة
OkHttp هو عميل HTTP فعال لـ Java وAndroid وKotlin، طورته شركة Square. توفر المكتبة واجهة برمجة تطبيقات منخفضة المستوى لتنفيذ طلبات HTTP مع دعم HTTP/2 وSPDY وWebSocket واستعادة الاتصال التلقائي عند فشل الشبكة.
ظهر OkHttp في عام 2013 كاستجابة للحاجة إلى عميل HTTP موثوق يحل مشاكل HttpURLConnection — عدم وجود تجمع اتصالات، وضعف دعم HTTP/2، وواجهة برمجة تطبيقات غير ملائمة. بحلول عام 2025، يُستخدم OkHttp على مستوى نظام Android API: OkHttp مضمن في تنفيذ HttpURLConnection منذ Android 4.4 (API 19).
وفقاً لـ Google I/O 2024، يعالج OkHttp أكثر من 70% من جميع طلبات HTTP في النظام البيئي لنظام Android. هذا ممكن لأن OkHttp يعمل كطبقة نقل لـ Retrofit وApollo GraphQL وFirebase والعديد من المكتبات الأخرى. يحصل المطورون على وظائف OkHttp تلقائياً دون الحاجة إلى إضافته صراحة.
هندسة OkHttp مبنية على سلسلة معترضات. يمر كل طلب عبر سلسلة من المعترضات التي يمكنها تعديل الطلب أو الاستجابة أو إحباط التنفيذ. تشبه هذه الهندسة نمط Chain of Responsibility وتسمح بالتوسع المرن.
عندما يرسل التطبيق طلباً، يقوم OkHttp بالخطوات التالية: يحل DNS، ويختار اتصالاً من التجمع (أو ينشئ اتصالاً جديداً)، ويفتح مصافحة TLS (إذا كان HTTPS)، ويرسل طلب HTTP، ويتلقى الاستجابة، ويعيدها إلى التطبيق. RealCall هي الفئة الداخلية التي تدير دورة الحياة الكاملة للطلب من الإنشاء إلى الإكمال.
يتولى OkHttp تلقائياً معالجة إعادة التوجيه (302، 301)، وإعادة محاولة الطلبات عند فشل الشبكة، واتباع بروتوكول keep-alive، ودعم ضغط gzip الشفاف. لا يحتاج المطور إلى كتابة كود لهذه العمليات — يقوم OkHttp بها تلقائياً بناءً على رؤوس الخادم.
HTTP/2 يسمح بإرسال طلبات متعددة عبر اتصال TCP واحد في وقت واحد، دون حظر الرأس (head-of-line blocking) المميز لـ HTTP/1.1. يستخدم OkHttp تلقائياً HTTP/2 إذا كان الخادم يدعمه، ويتحول بشفافية إلى HTTP/1.1 عند الضرورة.
تعدد إرسال HTTP/2 مهم بشكل خاص للتطبيقات المحمولة، حيث يمكن أن يتراوح زمن إنشاء الاتصال (TCP + TLS) بين 100–300 مللي ثانية. بدلاً من 10 اتصالات متسلسلة، يستخدم OkHttp اتجاهاً واحداً، مما يقلل زمن الوصول الإجمالي بنسبة 40–60% على أجهزة Android النموذجية ذات الاتصالات غير المستقرة.
Interceptor هي واجهة بطريقة واحدة intercept(Chain)، تستقبل طلباً وتنفذ إجراءات وتعيد استجابة. هناك نوعان من المعترضات: معترضات التطبيق (تضاف عبر addInterceptor) ومعترضات الشبكة (addNetworkInterceptor).
تعمل معترضات التطبيق قبل تشكيل طلب HTTP — ترى الطلب الأصلي والاستجابة النهائية بعد كل التحويلات. معترضات الشبكة تعمل على مستوى الشبكة: ترى الطلب بعد ضغط gzip، وإضافة رأس Content-Length، وإعادة التوجيه، وإعادة المحاولة. لا يتم استدعاء معترضات الشبكة إذا تم تقديم الاستجابة من ذاكرة التخزين المؤقت.
| نوع المعترض | طريقة الإضافة | متى يُستدعى | يرى التخزين المؤقت |
|---|---|---|---|
| Application Interceptor | addInterceptor() | قبل وبعد الطلب | نعم |
| Network Interceptor | addNetworkInterceptor() | على مستوى الشبكة | لا |
من الناحية العملية، تحل معترضات OkHttp ثلاث مهام رئيسية: التفويض (إضافة رأس Authorization)، التسجيل (HttpLoggingInterceptor لتصحيح الأخطاء)، وإعادة المحاولة (إعادة الطلب التلقائي عند فشل الشبكة). من خلال دمج معترضات متعددة، يمكن بناء خط أنابيب معالجة طلبات كامل دون تكرار الكود في كل استدعاء HTTP للتطبيق.
ترتيب إضافة المعترضات مهم: المعترض المضاف أولاً يُنفذ أولاً عند الدخول وآخراً عند الخروج. بالنسبة لـ NetworkInterceptor، يُحدد الترتيب بواسطة مكدس الشبكة. الترتيب الموصى به: AuthInterceptor (يضيف رمزاً مميزاً)، LoggingInterceptor (يسجل الطلب)، RetryInterceptor (يعيد المحاولة عند الفشل).
لتصحيح أخطاء طلبات الشبكة، يُستخدم HttpLoggingInterceptor — معترض جاهز من Square. يسجل الطريقة وعنوان URL والرؤوس وجسم الطلب والاستجابة. مستويات التسجيل: BASIC (الطريقة + URL + الرمز)، HEADERS (مع الرؤوس)، وBODY (الطلب والاستجابة بالكامل). BODY مفيد أثناء التطوير ولكن يتم تعطيله في الإنتاج لأسباب أمنية وأداء.
دعنا نلقي نظرة على طلب GET أساسي باستخدام OkHttp. أولاً، يتم إنشاء OkHttpClient — كائن ثقيل يُنشأ مرة واحدة ويعاد استخدامه. ثم يتم تشكيل Request بعنوان URL، ويُنفذ الطلب بشكل متزامن عبر execute أو بشكل غير متزامن عبر enqueue.
val client = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url("https://api.github.com/users/octocat")
.header("Accept", "application/vnd.github.v3+json")
.build()
val response = client.newCall(request).execute()
println(response.body()?.string())
للتنفيذ غير المتزامن، يُستخدم أسلوب enqueue الذي يقبل Callback. ينفذ OkHttp الطلب في خلفية الموضوع ويعيد النتيجة في الاستدعاء على نفس الموضوع. للتبديل إلى الموضوع الرئيسي لنظام Android، استخدم Handler أو coroutines.
client.newCall(request).enqueue(object : Callback {
override fun onFailure(
call: Call, e: IOException
) {
println("فشل الطلب: ${e.message}")
}
override fun onResponse(
call: Call, response: Response
) {
println(response.body()?.string())
}
})
Interceptor مخصص يضيف رمز Bearer مميزاً إلى كل طلب. يتحقق المعترض من وجود رأس Authorization، وإذا لم يكن الرمز المميز مضبوطاً بعد، يضيفه من وحدة التخزين. عند استجابة 401، يمكن للمعترض تحديث الرمز المميز عبر Authenticator.
class AuthInterceptor(
private val tokenProvider: () -> String?
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val token = tokenProvider.invoke()
val request = originalRequest.newBuilder()
.header("Authorization", "Bearer $token")
.build()
return chain.proceed(request)
}
}
تجمع الاتصالات (ConnectionPool) هو تحسين رئيسي في OkHttp يسمح بإعادة استخدام اتصالات TCP لطلبات متعددة. بدلاً من إنشاء مأخذ توصيل جديد لكل طلب، يخزن OkHttp ما يصل إلى 5 اتصالات خاملة (افتراضياً) لمدة 5 دقائق، مما يقلل زمن الوصول بنسبة 30–70% للطلبات المتكررة لنفس المضيف.
يتم تنفيذ التخزين المؤقت للاستجابات عبر فئة Cache. لتمكين التخزين المؤقت، يكفي تحديد الدليل والحجم الأقصى في OkHttpClient.Builder. يخزن OkHttp تلقائياً استجابات GET وفقاً لرؤوس Cache-Control وExpires وETag، ويعيد البيانات المخزنة مؤقتاً دون طلب شبكة إذا لم تكن قديمة.
val cacheDir = File(context.cacheDir, "http-cache")
val cache = Cache(cacheDir, 10L * 1024 * 1024)
val client = OkHttpClient.Builder()
.cache(cache)
.connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
.build()
التكوين الصحيح للتجمع والتخزين المؤقت مهم بشكل خاص للتطبيقات ذات الطلبات المتكررة — خلاصات الأخبار والدردشات وتحديثات البيانات. بدون تجمع، يتطلب كل اتصال TCP مصافحة ثلاثية (SYN، SYN-ACK، ACK) وربما مصافحة TLS (2–3 جولات)، مما يضيف 100–500 مللي ثانية لكل طلب.
يدعم OkHttp أيضاً WebSocket عبر فئة RealWebSocket. يتم إنشاء اتصال WebSocket من خلال مصافحة HTTP (101 Switching Protocols) ثم يتحول إلى بروتوكول ثنائي الاتجاه. يرسل OkHttp تلقائياً إطارات ping للحفاظ على الاتصال نشطاً ويعيد الاتصال عند الانقطاع. WebSocket من OkHttp متوافق مع نقاط النهاية القياسية مثل wss://echo.websocket.org.
إنشاء OkHttpClient لكل طلب هو الخطأ الأكثر شيوعاً. يحتوي OkHttpClient على تجمع اتصالات وذاكرة تخزين مؤقت وتجمع خيوط. إنشاء مثيل جديد لكل طلب لا يهدر الذاكرة فحسب، بل يفقد أيضاً فائدة إعادة استخدام الاتصالات. يجب أن يكون OkHttpClient مفردة عبر حاوية DI.
تجاهل إغلاق Response.body() يؤدي إلى تسرب الموارد. يحتوي ResponseBody على InputStream يجب إغلاقه بعد القراءة. إذا تم استخدام body().string() أو body().bytes()، يغلق OkHttp التدفق تلقائياً، ولكن عند قراءة body().byteStream() أو body().charStream()، يلزم استدعاء close() صريح في كتلة finally.
عدم معالجة المهلة مشكلة أخرى. افتراضياً، لدى OkHttp connectTimeout مدته 10 ثوانٍ، وreadTimeout مدته 10 ثوانٍ، وwriteTimeout مدته 10 ثوانٍ. للتطبيقات المحمولة ذات الاتصالات غير المستقرة، يُوصى بتعيين connectTimeout من 15–30 ثانية وreadTimeout من 15–30 ثانية، وإلا سينتظر المستخدم طويلاً مع إشارة ضعيفة.
الأسئلة الشائعة
OkHttp هو عميل HTTP منخفض المستوى مع إدارة يدوية للطلب والاستجابة. Retrofit هو تجريد عالي المستوى مع شروح. يُستخدم OkHttp كطبقة نقل لـ Retrofit، ولكنه يمكن أن يعمل بشكل مستقل دون مكتبات إضافية.
يستخدم OkHttp SSLSocketFactory لمصافحة TLS. تدعم المكتبة CertificatePinner لتثبيت الشهادات، وTrustManager للتحقق المخصص، وHostnameVerifier للتحقق من اسم المضيف مقابل الشهادة.
الطلبات المتزامنة تطرح IOException عند مشاكل الشبكة. الطلبات غير المتزامنة تتلقى استدعاء onFailure مع IOException. لأخطاء HTTP (4xx، 5xx)، تعتبر الاستجابة ناجحة — يتم التحقق من رمز الخطأ عبر response.isSuccessful().
نعم، OkHttp لديه دعم مدمج لـ WebSocket عبر فئة WebSocket وWebSocketListener. بعد إنشاء الاتصال، يسمح WebSocket بإرسال واستقبال الرسائل في الوقت الفعلي دون طلبات HTTP متكررة.
قم بتعطيل إعادة التوجيه التلقائي عبر followRedirects(false) وfollowSslRedirects(false) في OkHttpClient.Builder. هذا مفيد عندما تحتاج إلى معالجة إعادة التوجيه يدوياً، على سبيل المثال، لاستخراج رمز مميز من عنوان URL لإعادة التوجيه.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.