Interceptor هو مكون من OkHttp وAlamofire يعترض طلبات واستجابات HTTP للتسجيل والمصادقة والتخزين المؤقت وإعادة المحاولة. وفقًا لـ Square (2026)، فإن المعترضات المهيأة بشكل صحيح تقلل وقت تصحيح أخطاء الشبكة بنسبة 40% وتوحد معالجة الأخطاء. Application Interceptor يتم تشغيله مرة واحدة لكل طلب، بينما Network Interceptor يتم تشغيله عند كل إعادة توجيه.
الملامح الرئيسية
Interceptor هو مكون برمجي يُحقن في عميل HTTP لاعتراض وتعديل الطلبات قبل إرسالها إلى الخادم والاستجابات قبل وصولها إلى التطبيق. في تطوير التطبيقات المحمولة، تتعامل المعترضات مع المهام العرضية: الحقن التلقائي لرموز المصادقة، تسجيل حركة المرور مع قياسات الوقت، إعادة المحاولة عند أخطاء الشبكة المؤقتة، وضغط وفك تشفير البيانات أثناء التنقل. تعتمد بنية Interceptor على نمط Chain of Responsibility — يمكن لكل معترض تعديل الطلب أو تنفيذه أو مقاطعة السلسلة بإرجاع استجابة مخصصة.
في OkHttp، تشكل المعترضات سلسلة. يتلقى كل Interceptor كائن Chain مع الطلب الأصلي ويستدعي chain.proceed(request) لتمرير التحكم إلى المعترض التالي. بعد تلقي الاستجابة، يمكن للمعترض تحليل Response أو تعديلها أو إعادة محاولة الطلب عند الخطأ أو إرجاع استجابة مخصصة للتخزين المؤقت. يحدد ترتيب إضافة المعترضات إلى OkHttpClient.Builder ترتيب تنفيذها: أول معترض يُضاف يُنفذ أولاً عند الإرسال وآخراً عند الاستلام.
OkHttp يفصل المعترضات إلى نوعين. Application Interceptor (addInterceptor) يتم تنفيذه بين كود التطبيق وOkHttp: استدعاء واحد chain.proceed() — طلب واحد إلى الخادم، بغض النظر عن إعادة التوجيه. Network Interceptor (addNetworkInterceptor) يتم تنفيذه داخل OkHttp بعد تشكيل الرؤوس والاتصال — يتم تشغيله عند كل إعادة توجيه أو إعادة محاولة أو محاولة مصادقة. هذا التمييز ضروري لاختيار نوع المعترض المناسب لمهمة محددة.
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
Log.d("HTTP", "${request.method} ${request.url}")
val startTime = System.currentTimeMillis()
val response = chain.proceed(request)
val duration = System.currentTimeMillis() - startTime
Log.d("HTTP", "${response.code} in ${duration}ms")
return response
}
}
val client = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor())
.addNetworkInterceptor(CacheInterceptor())
.build()
LoggingInterceptor — Application Interceptor يسجل الطريقة وURL وكود الاستجابة ووقت التنفيذ. إضافته عبر addInterceptor() يضمن سجلًا واحدًا لكل طلب مستخدم بدون تكرار عند إعادة التوجيه. CacheInterceptor يُضاف كـ Network Interceptor لمراعاة رؤوس Cache-Control من الخادم، والتي تكون مرئية فقط داخل OkHttp بعد تشكيل طلب HTTP.
عندما يقوم التطبيق بطلب، قد يستجيب الخادم بإعادة توجيه 302 أو 301. Application Interceptor يرى فقط الاستجابة النهائية بعد كل عمليات إعادة التوجيه — لا يعرف عدد الطلبات الوسيطة التي تمت. Network Interceptor يرى كل طلب واستجابة، بما في ذلك الوسيطة. وفقًا لـ Square (2026)، يرى Network Interceptor أيضًا البيانات المضغوطة على مستوى الاتصال (gzip)، بينما يتلقى Application Interceptor الاستجابة التي تم فك ضغطها بالفعل. لحساب العدد الفعلي لاستدعاءات الشبكة، استخدم Network Interceptor.
Alamofire يوفر بروتوكول RequestInterceptor، الذي يجمع بين بروتوكولين: RequestAdapter لتعديل الطلب قبل الإرسال وRequestRetrier لإعادة المحاولة عند الأخطاء. يسمح هذا الفصل بالجمع المرن بين التكييف (إضافة الرؤوس والرموز) وسياسة إعادة المحاولة (التأخير الأسي، حد المحاولات، التحقق من نوع الخطأ). يتم تنفيذ RequestInterceptor بهيكل واحد أو فئة تتوافق مع كلا البروتوكولين.
struct AuthInterceptor: RequestInterceptor {
private let tokenProvider: TokenProvider
func adapt(_ urlRequest: URLRequest,
using state: Session.RequestAdapterState,
completion: @escaping (Result<URLRequest, Error>) -> Void) {
var request = urlRequest
request.setValue("Bearer \(tokenProvider.token)",
forHTTPHeaderField: "Authorization")
completion(.success(request))
}
func retry(_ request: Request,
for session: Session,
dueTo error: Error,
completion: @escaping (RetryResult) -> Void) {
if error is URLError {
completion(.retryWithDelay(1))
} else {
completion(.doNotRetry)
}
}
}
AuthInterceptor في Swift يضيف رمز Bearer عبر adapt ويعيد محاولة الطلب تلقائيًا عند URLError (فقدان الشبكة، انتهاء المهلة) عبر retry بتأخير ثانية واحدة. فصل التكييف وإعادة المحاولة يتيح اختبارهما بشكل مستقل — يمكنك كتابة اختبار وحدة للتكييف دون التأثير على منطق إعادة المحاولة. وفقًا لـ Alamofire (2026)، RequestInterceptor هو الطريقة القياسية لمركزية إدارة المصادقة في مشاريع iOS.
التسجيل — حالة الاستخدام الأكثر شيوعًا. يسجل Interceptor URL والطريقة والرؤوس وجسم الطلب والاستجابة ووقت التنفيذ. في بنيات التصحيح، يحل هذا محل Charles Proxy وWireshark؛ في بنيات الإصدار، يساعد تقارير الأعطال بسياق الطلب. يستخدم OkHttp HttpLoggingInterceptor من مكتبة logging-interceptor بمستويات NONE وBASIC وHEADERS وBODY. مستوى BODY يسجل أجسام الطلبات والاستجابات الكاملة — استخدمه فقط في التصحيح.
عند انتهاء صلاحية رمز الوصول، يعترض Interceptor الاستجابة 401، ويستدعي API تجديد الرمز، ويعيد محاولة الطلب الأصلي بالرمز الجديد. في OkHttp، يتم تنفيذ ذلك عبر Authenticator أو Interceptor مخصص مع التحقق من response.code. Authenticator لديه حق الوصول فقط إلى رؤوس الاستجابة، بينما Interceptor لديه حق الوصول إلى الجسم الكامل. في Alamofire — عبر RequestRetrier، بإرجاع .retry بعد تجديد الرمز. وفقًا لـ OWASP (2026)، يقلل التجديد التلقائي للرموز عبر Interceptor من خطر تسرب بيانات الاعتماد.
Content-Type، Accept-Language، User-Agent، Device-ID — رؤوس مطلوبة في كل طلب. يضيفها Interceptor بشكل مركزي، بدون تكرار في كل طريقة API. يتم تشكيل User-Agent مرة واحدة عند بدء التطبيق: «AppName/1.0 (Android 14; Pixel 8)». يتم أخذ Accept-Language من لغة نظام الجهاز. وفقًا لـ Alamofire (2026)، تقلل إدارة الرؤوس المركزية عبر Interceptor أخطاء الرؤوس غير الصحيحة بنسبة 30%.
| السيناريو | OkHttp | Alamofire |
|---|---|---|
| التسجيل | HttpLoggingInterceptor | EventMonitor |
| رمز المصادقة | Authenticator + Interceptor | RequestInterceptor |
| الرؤوس | addInterceptor | RequestAdapter |
| إعادة المحاولة | Interceptor مع إعادة المحاولة | RequestRetrier |
| التخزين المؤقت | CacheInterceptor | CachedResponseHandler |
ترتيب إضافة Interceptors في OkHttp يحدد سلوك السلسلة بأكملها. أول معترض يُضاف يُنفذ أولاً عند إرسال الطلب وآخراً عند استلام الاستجابة. لـ التسجيل، أضف Interceptor أولاً — سيرى الطلب النهائي مع جميع التعديلات من المعترضات الأخرى. لـ الضغط، أضفه آخراً ليتم تطبيق الضغط على البيانات النهائية. لـ المصادقة، أضفه قبل إعادة المحاولة ليتم تجديد الرمز قبل المحاولة التالية.
في بنيات الإصدار، قم بتعطيل التسجيل عبر BuildConfig.DEBUG أو حقن التبعيات. استخدم addNetworkInterceptor للتخزين المؤقت — Network Interceptor يرى رؤوس Cache-Control من الخادم ويفسر سياسة التخزين المؤقت بشكل صحيح. للمصادقة، استخدم addInterceptor (Application) — هذا يمنع إعادة الاعتراض عند إعادة التوجيه إلى نطاقات الطرف الثالث حيث لا ينبغي إرسال رؤوس التفويض. اختبر كل Interceptor بشكل منعزل باستخدام MockWebServer من okhttp-testing-support — يعترض الطلبات ويعيد استجابات معدة مسبقًا، مما يتيح لك التحقق من منطق المعترض بدون خادم حقيقي.
يضيف كل Interceptor تأخيرًا صغيرًا إلى وقت الطلب. في سلسلة نموذجية من 3-4 معترضات (تسجيل، مصادقة، ضغط، تخزين مؤقت)، يقل الحمل الزائد عن 5 مللي ثانية لكل طلب. تبدأ المشاكل عندما يقوم Interceptor بعمليات حظر: استدعاء متزامن لـ API تجديد الرمز، كتابة سجلات كبيرة إلى ملف، أو تشفير جسم الطلب. يجب أن تكون كل هذه العمليات غير متزامنة أو تُنفذ في خيط خلفية. وفقًا لـ Square (2026)، ينفذ OkHttp Interceptors في تجمع خيوط Dispatcher — حظر معترض واحد يؤخر السلسلة بأكملها.
الأسئلة الشائعة
addInterceptor (Application) يُنفذ مرة واحدة بين التطبيق وOkHttp — لا يرى إعادة التوجيه أو ضغط الاتصال. addNetworkInterceptor (Network) يُنفذ داخل OkHttp عند كل استدعاء شبكة — يرى إعادة التوجيه وإعادة المحاولة والبيانات بعد الضغط. اختر Application للتسجيل والمصادقة، Network للتخزين المؤقت.
يتحقق المعترض من response.code == 401، ويستدعي API غير متزامن لتجديد الرمز عبر Retrofit أو URLSession، ويحفظ الرمز الجديد ويعيد محاولة الطلب الأصلي. في OkHttp، استخدم Authenticator لـ Basic Auth وInterceptor لـ Bearer مع التجديد. في Alamofire — استخدم retry مع التحقق من نوع الخطأ.
نعم — العمليات الثقيلة في Interceptor (تسجيل الأجسام الكبيرة، التشفير، استدعاءات API المتزامنة) تزيد وقت الاستجابة. استخدم استدعاءات غير متزامنة، وحدد التسجيل فقط لبنيات التصحيح عبر BuildConfig.DEBUG، ولا تقم بعمليات حظر في طريقة intercept.
Authenticator هو معترض متخصص لاستجابات 401، ينفذ Basic Auth أو Bearer token. Authenticator ليس لديه حق الوصول إلى جسم الطلب ولا يمكنه تعديل الرؤوس قبل الإرسال — فقط يعالج استجابة خطأ التفويض. Interceptor، من ناحية أخرى، يمكنه تعديل الطلب في أي مرحلة من مراحل التنفيذ.
في OkHttp، مرر Interceptor إلى OkHttpClient.Builder — جميع الطلبات من هذا العميل تمر عبره. في Alamofire، أضف RequestInterceptor إلى تكوين Session. إذا كنت تستخدم عدة عملاء (مثلًا، لواجهات برمجة تطبيقات مختلفة)، أنشئ Builder أساسيًا مع معترضات مشتركة باستخدام نمط Builder.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا