الوسيطة هي طبقة برمجية وسيطة تعالج البيانات قبل أو بعد المنطق الرئيسي للتطبيق، وتعزل المهام الشاملة عن كود الأعمال. وفقًا لـ Redux (2026)، تقلل الوسيطة من تكرار كود التسجيل والمصادقة بنسبة 40% من خلال المعالجة المركزية. وسيطة Redux هي مثال كلاسيكي، لكن النمط يُستخدم على نطاق أوسع: Ktor Client وBloc وExpress.js وDio.
النقاط الرئيسية
الوسيطة هي طبقة برمجية تقع بين مكونين من مكونات النظام، تعترض البيانات وتعالجها قبل تمريرها إلى المكون الهدف. في تطوير الجوال، تُستخدم الوسيطة في ثلاثة سياقات رئيسية: إدارة الحالة (Redux، Bloc)، اتصالات HTTP (Ktor Client، Dio)، ومعالجة الأحداث (EventBus، NotificationCenter). القيمة الأساسية هي عزل المهام الشاملة (التسجيل، المصادقة، التحليلات) عن منطق المجال للتطبيق. بدلاً من إضافة استدعاءات تحليلات إلى كل شاشة، تقوم الوسيطة بذلك مركزيًا.
تنفذ الوسيطة نمط Pipe and Filter: كل مكون وسيطة يستقبل البيانات ويعالجها ويمررها إلى الحلقة التالية في السلسلة. يحدد ترتيب توصيل الوسيطة تسلسل المعالجة — أول وسيطة تستقبل البيانات الخام، وآخرها يمررها إلى المعالج الهدف. وفقًا لـ JetBrains (2026)، تسمح هذه الهندسة بإضافة أو إزالة الوسيطة دون تغيير الكود الموجود، مما يبسط الاختبار واختبار A/B للوحدات التجريبية.
الوسيطة هي نمط عام، وInterceptor هو حالة خاصة لها في HTTP. الوسيطة تعمل مع أي تدفقات بيانات: الإجراءات في Redux، الأحداث في Bloc، طلبات HTTP في Ktor. Interceptor دائمًا مرتبط بطبقة الشبكة ويعمل فقط مع Request/Response. فهم هذا الفرق يساعد في اختيار التجريد الصحيح: لتسجيل إجراءات المستخدم — وسيطة، لإضافة رؤوس — Interceptor. في المشاريع الكبيرة، غالبًا ما يتعايش كلا النمطين: الوسيطة تدير الحالة، وInterceptor يتعامل مع اتصالات HTTP.
وسيطة Redux تعترض كل إجراء dispatch قبل أن يصل إلى reducer. يتيح ذلك تسجيل الإجراءات، وتنفيذ الطلبات غير المتزامنة عبر Redux Thunk أو Redux Saga، وتعديل الإجراء أو إلغاؤه بشروط. تستقبل كل وسيطة store (وصول إلى الحالة)، next (مرجع إلى الوسيطة التالية أو reducer) وaction، وتقرر ما تفعله: تمرير الإجراء، تعديله أو حظره.
Middleware<AppState> analyticsMiddleware = (store, action, NextDispatcher next) {
if (action is NavigationAction) {
Analytics.logEvent(action.screenName);
}
return next(action);
};
final store = Store<AppState>>(
reducer,
initialState,
middleware: [analyticsMiddleware]
);
مثال لـ analyticsMiddleware بلغة Dart لـ Flutter Redux. الوسيطة تعترض جميع NavigationAction، وتسجل اسم الشاشة في نظام التحليلات وتستدعي next(action) لمواصلة السلسلة. إذا لم يتم استدعاء next، فلن يصل الإجراء إلى reducer — بهذه الطريقة يمكن تنفيذ التنقل الشرطي أو حظر الإجراءات غير المرغوب فيها. يحدد ترتيب الوسيطة في المصفوفة تسلسل المعالجة.
Redux Thunk هي وسيطة تسمح بإرسال ليس فقط كائنات إجراء ولكن أيضًا دوال. تستقبل الدالة dispatch وgetState، ويمكنها تنفيذ عمليات غير متزامنة (طلبات API عبر عميل HTTP، قراءة من قاعدة البيانات) وإرسال إجراءات عادية عند الانتهاء. هذا هو النهج القياسي لطلبات الشبكة في تطبيقات Redux. Redux Saga تستخدم المولدات (yield) لسيناريوهات أكثر تعقيدًا: إلغاء الطلبات، حالات السباق، العمليات المتوازية وتباعد إدخال المستخدم. وفقًا لـ Redux Saga (2026)، فإن coroutines Saga أسهل في الاختبار والتصحيح من استدعاءات Thunk المتداخلة.
Ktor Client من JetBrains يبني معالجة HTTP بناءً على pipeline الوسيطة. كل مرحلة طلب — إعداد الاتصال، إرسال الرؤوس، قراءة الاستجابة — ممثلة بمرحلة منفصلة في pipeline. يقوم المطور بتثبيت الإضافات (الوسيطة) عبر client.install { }، للحصول على سلسلة معالجة. يحدد ترتيب التثبيت أي وسيطة تعالج البيانات أولاً: Logging، Auth، ContentNegotiation، Caching.
val client = HttpClient {
install(Logging) {
level = LogLevel.BODY
}
install(Auth) {
bearer {
loadTokens { BearerTokens("access", "refresh") }
}
}
install(ContentNegotiation) {
json(Json { ignoreUnknownKeys = true })
}
install(HttpTimeout) {
requestTimeoutMillis = 15000
}
}
إعداد Ktor Client مع إضافات وسيطة مثبتة. Logging — يكتب جسم الطلب والاستجابة. Auth — يضيف تلقائيًا رمز Bearer مع دعم refresh. ContentNegotiation — يسلسل/يفك تسلسل JSON. HttpTimeout — يحدد مهلات. كل إضافة مستقلة: في بيئة الاختبار يمكن تعطيل Auth عن طريق استبدال إعداد العميل دون تغيير كود الطلبات.
Dio هو عميل HTTP شائع لـ Flutter، يستخدم Interceptor كوسيطة. يعترض Interceptor RequestOptions قبل الإرسال وResponse بعد الاستلام، ويدعم سلسلة من المعترضات المتعددة. Dio Interceptor مماثل لـ OkHttp Interceptor في Dart/Flutter. وفقًا لـ Dio (2026)، فإن RetryInterceptor وLogInterceptor هما الوسيطة الأكثر استخدامًا في مشاريع Flutter.
Bloc ليس لديه وسيطة مدمجة كمكون منفصل، لكن النمط يُطبق عبر BlocObserver — مراقب عالمي يستقبل أحداث كل كتلة في التطبيق. يتم استدعاء BlocObserver.onEvent قبل معالجة كل حدث، وonTransition عند كل انتقال حالة، وonError عند كل استثناء. هذه وسيطة كاملة للتحليلات والتسجيل والإبلاغ عن الأعطال ومراقبة الأداء.
class AppBlocObserver extends BlocObserver {
@override
void onEvent(Bloc bloc, Object? event) {
Crashlytics.log("${bloc.runtimeType}: $event");
super.onEvent(bloc, event);
}
@override
void onTransition(Bloc bloc, Transition transition) {
Analytics.log(transition.eventName());
super.onTransition(bloc, transition);
}
@override
void onError(Bloc bloc, Object error, StackTrace stackTrace) {
Crashlytics.recordError(error, stackTrace);
super.onError(bloc, error, stackTrace);
}
}
BlocOverrides.runZoned(() {
runApp(MyApp());
}, blocObserver: AppBlocObserver());
مثال لـ AppBlocObserver — وسيطة لـ Bloc في Dart. onEvent يسجل كل حدث في Crashlytics، onTransition يرسل أحداثًا إلى التحليلات، onError يكتب الاستثناءات في الإبلاغ عن الأعطال. الاتصال عبر BlocOverrides.runZoned يجعل المراقب عالميًا لجميع الكتل دون تغيير كودها. لتعطيله في الاختبارات، يكفي تمرير مراقب فارغ أو عدم تجاوز BlocOverrides.
الوسيطة فعالة للمهام التي تؤثر على العديد من المكونات: التسجيل، المصادقة، التحليلات، التخزين المؤقت، مراقبة الأداء. استخدم الوسيطة عندما يتكرر نفس المنطق في أجزاء مختلفة من التطبيق — إضافة رمز مميز إلى كل طلب، تسجيل كل إجراء مستخدم، تحليلات كل انتقال بين الشاشات. وفقًا لـ Dio (2026)، تقلل المعالجة المركزية عبر الوسيطة من الأخطاء بنسبة 25% مقارنة بتكرار الكود في كل مكون على حدة.
الخطأ الأكثر شيوعًا هو الترتيب غير الصحيح للوسيطة، عندما يتوقع أول معترض بيانات يضيفها الثاني. ثاني أكثر خطأ شيوعًا هو العمليات الحاجزة في الوسيطة على الخيط الرئيسي: كتابة ملف، استدعاءات HTTP متزامنة، تشفير. الثالث هو عدم معالجة الاستثناءات: إذا ألقت الوسيطة استثناءً، تنكسر السلسلة بأكملها ولن يصل الإجراء إلى reducer أو لن يُرسل الطلب. دائمًا لف منطق الوسيطة في try-catch وسجل الأخطاء في Crashlytics أو Sentry دون كسر السلسلة. راجع سلسلة الوسيطة بانتظام أثناء مراجعات الكود — هذا يمنع تدهور البنية.
الأسئلة الشائعة
Interceptor هو حالة خاصة من الوسيطة لاتصالات HTTP. الوسيطة هي نمط أوسع: يمكنها معالجة الإجراءات (Redux)، الأحداث (Bloc)، HTTP (Ktor) وأي تدفقات بيانات. Interceptor دائمًا مرتبط بطبقة الشبكة ويعمل فقط مع Request/Response.
استخدم طريقة المصنع أو حاوية DI (Dagger، Koin، GetIt) التي تعيد مجموعة مختلفة من الوسيطة للبيئة التطويرية والإنتاجية. في Redux، مرر مصفوفة فارغة في الاختبارات. في Ktor، استخدم HttpClient اختبارية بدون إضافات. المبدأ الرئيسي هو أن الوسيطة لا يجب أن تكون مشفرة بشكل ثابت في الكود.
نعم — الوسيطة تعدل الإجراء قبل تمريره إلى reducer أو الوسيطة التالية. على سبيل المثال، يمكن لوسيطة Redux إضافة بيانات وصفية (userId، timestamp، deviceId) إلى كل إجراء دون تغيير كود المرسل. القاعدة الرئيسية هي عدم تحوير الكائن الأصلي بل إنشاء كائن جديد عبر عامل الانتشار.
في Ktor، المصطلحان قابلان للتبادل — وسيطة Ktor Client وإضافة يعنيان نفس الشيء. كل إضافة تنفذ HttpClientPlugin ويتم تثبيتها عبر client.install { }. جميع الإضافات تُدمج في pipeline الطلب، مشكلة سلسلة معالجة.
عن طريق تجاوز BlocObserver.onError — معالج عالمي يُستدعى عند كل استثناء في أي كتلة. هذا بديل لـ try-catch في كل كتلة: وسيطة واحدة تعالج الأخطاء مركزيًا، وتكتبها في Crashlytics وتعرض snackbar للمستخدم.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا