Dio هو عميل HTTP قوي لـ Dart و Flutter، تم تطويره بواسطة المهندس الصيني Wenda Wang. توفر المكتبة API متقدمة مع دعم للمعترضات و FormData وتحميل الملفات وإلغاء الطلبات. وفقًا لـ pub.dev, 2025، Dio هو عميل HTTP الأكثر شعبية في نظام Flutter البيئي مع أكثر من 8 آلاف نجمة على GitHub.
الملامح الرئيسية
Dio هي مكتبة عميل HTTP قوية للغة Dart، الأكثر استخدامًا في تطبيقات Flutter. توفر Dio API غنية مع دعم للمعترضات والتكوين العام والمحولات و FormData وتحميل الملفات وإدارة المهلات بمرونة، مما يجعلها الخيار الأساسي للاتصال بالشبكة في مجتمع Flutter.
تم إنشاء المكتبة بواسطة Wenda Wang في عام 2018 كبديل لـ HttpClient المدمج في dart:io، الذي كان يفتقر إلى العديد من الإمكانيات الحديثة: تكوين موحد لجميع الطلبات ومعترضات وتسلسل تلقائي. بحلول عام 2025، تجاوز Dio حزمة http من فريق Dart من حيث الشعبية، محتلاً المركز الأول بين عملاء HTTP في نظام Flutter البيئي وفقًا لـ pub.dev.
يدعم Dio ثلاثة محولات: DartNativeAdapter (افتراضيًا على Android و iOS و Desktop) و BrowserAdapter (على Web) و IOAdapter. يتم اختيار المحول تلقائيًا حسب المنصة. يوفر Dio أيضًا واجهة موحدة لجميع منصات Flutter — Android و iOS و Web و macOS و Windows و Linux.
تعتمد بنية Dio على سلسلة معالجات. يمر كل طلب عبر سلسلة من المعترضات التي يمكنها تعديل الطلب (InterceptorsWrapper.onRequest) أو الاستجابة (onResponse) أو معالجة خطأ (onError). بعد المعترضات، يصل الطلب إلى المحولات (Transformer) التي تحول البيانات قبل الإرسال.
يتم تكوين مثيل Dio من خلال كائن BaseOptions يحتوي على عنوان URL الأساسي والرؤوس الافتراضية والمهلات ونوع الاستجابة (JSON أو stream أو plain) ومعاملات الاستعلام وتنسيق البيانات. تنطبق هذه الإعدادات على جميع الطلبات ولكن يمكن تجاوزها في طلب معين. يوفر BaseOptions نقطة تكوين واحدة للتطبيق بأكمله، مما يبسط تغييرات نقطة النهاية أو إضافة رؤوس عامة.
كل طلب في Dio يعيد Response<T>، حيث T هو نوع البيانات بعد معالجة المحول. افتراضيًا، يقوم Dio تلقائيًا بتحويل استجابات JSON إلى Map<String, dynamic>. للاستجابات المنمطة، يُستخدم Dio مع حزم التسلسل: json_serializable أو freezed أو built_value. تحتوي Response على data و headers و statusCode و requestOptions وبيانات إضافية.
يتم إنشاء التكوين الأساسي عبر Dio(BaseOptions). يمكن تعيين baseUrl لجميع الطلبات و connectTimeout و receiveTimeout ورؤوس content-type و accept بالإضافة إلى queryParameters. تنطبق كل هذه المعاملات على كل طلب، مما يلغي تكرار الكود ويتمركز إدارة إعدادات الشبكة.
يدعم Dio وضعي تسلسل: JSON افتراضيًا (responseType: ResponseType.json) وتدفقي (ResponseType.stream). في وضع التدفق، يعيد Response.data ResponseBody يمكن قراءته بأجزاء. هذا مناسب لملفات الحمولة الكبيرة حيث لا يكون تحميل كل شيء في الذاكرة مرغوبًا. الوضع plain يعيد سلسلة نصية خام دون تحليل JSON تلقائي.
المعترضات هي الآلية الرئيسية لـ Dio لاعتراض وتعديل الطلبات والاستجابات والأخطاء. تحل محل Interceptor من OkHttp وإضافات Ktor تمامًا، ولكن مع API خاص بـ Dart ودعم غير متزامن عبر Future. يمكن إضافة المعترضات في التكوين العام لـ Dio أو للطلبات الفردية.
| طريقة المعترض | الغرض | مثال استخدام |
|---|---|---|
| onRequest | تعديل الطلب قبل الإرسال | إضافة رمز التفويض |
| onResponse | معالجة الاستجابة الناجحة | تحويل البيانات إلى كائنات DTO |
| onError | معالجة خطأ الطلب | إعادة محاولة تلقائية عند 503 |
LogInterceptor المدمج يسجل كل طلب: الطريقة وعنوان URL والرؤوس والجسم ووقت التنفيذ. له وضعان: مضغوط (سطر واحد لكل طلب) وكامل (معلومات كاملة مع الجسم). LogInterceptor مفيد بشكل خاص أثناء التطوير، لكن يُنصح بتعطيله في إصدارات الإصدار باستخدام imports شرطية أو علامة عامة.
يتم إنشاء المعترضات المخصصة عبر فئة InterceptorsWrapper. يمكن تجاوز طريقة واحدة أو اثنتين أو الثلاثة (onRequest و onResponse و onError). ينفذ Dio المعترضات بدقة حسب ترتيب إضافتها إلى قائمة المعترضات. إذا لم يستدع المعترض handler.next()، تنقطع السلسلة ولا تصل الاستجابة أو الخطأ إلى التطبيق.
للمصادقة في Dio، يُستخدم معترض يضيف رمز Bearer إلى رأس Authorization. إذا أعاد الخادم 401، يحاول المعترض في onError تحديث الرمز عبر طلب تحديث ويعيد الطلب الأصلي بالرمز الجديد. هذا النمط يسمى token refresh interceptor ويتم تنفيذه عبر DioException بالتحقق من response?.statusCode == 401.
يوفر Dio دعمًا مدمجًا لإعادة المحاولة عبر حزمة dio_smart_retry أو RetryInterceptor مخصص. إعادة المحاولة مهمة لتطبيقات الجوال: عند فقدان الاتصال لمدة 2-3 ثوانٍ، يطرح Dio DioException من نوع connectionTimeout أو connectionError. يلتقط RetryInterceptor هذا الاستثناء ويعيد الطلب حتى 3 مرات مع تأخير أسي (1ث و 2ث و 4ث)، مما يحسن موثوقية التطبيق في ظروف الشبكة غير المستقرة.
لنلق نظرة على طلب GET أساسي عبر Dio. يتم إنشاء مثيل مع BaseOptions، مع تعيين عنوان URL الأساسي والمهلات. يتم تنفيذ الطلب عبر طريقة get()، التي تعيد Response مع بيانات بتنسيق Map.
final dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com',
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
headers: {
'Accept': 'application/vnd.github.v3+json',
},
))
final response = await dio.get('/users/octocat')
print(response.data['تسجيل الدخول'])
لـ طلب POST مع جسم JSON، يتم تمرير كائن Map أو DTO مخصص. يقوم Dio تلقائيًا بتسلسل Map إلى JSON عبر jsonEncode. لـ DTOs المنمطة، يُستخدم خيار queryParameters أو حقل data أو Transformer مخصص.
final data = {
'name': 'my-project',
'description': 'Created via Dio',
'private': false,
}
final response = await dio.post(
'/user/repos',
data: data,
options: Options(
contentType: ContentType.json.value,
),
)
print(response.data['المعرف'])
معترض مخصص يضيف رمز Bearer إلى كل طلب. يتم تشغيل طريقة onRequest قبل الإرسال، معدلة الرؤوس. عند استجابة 401، يمكن للمعترض تحديث الرمز وإعادة الطلب عبر طريقة dio.fetch(requestOptions).
class AuthInterceptor extends InterceptorsWrapper {
final String token
AuthInterceptor(this.token)
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers['Authorization'] = 'Bearer $token'
handler.next(options)
}
}
dio.interceptors.add(AuthInterceptor('ghp_abc123'))
يبسط Dio تحميل الملفات عبر FormData. لإرسال ملف، يتم إنشاء MultipartFile من File أو Bytes أو AssetBundle. يقوم FormData تلقائيًا بتعيين رأس multipart/form-data مع الحدود والتشفير الصحيحين. يدعم Dio تقدم التحميل عبر onSendProgress.
لتنزيل الملفات، تُستخدم طريقة download()، التي تحفظ تدفق البيانات مباشرة في ملف. يدعم Dio استئناف التنزيلات المتقطعة عبر رأس Range، وهو مفيد بشكل خاص للملفات الكبيرة. يتم تتبع تقدم التنزيل عبر onReceiveProgress، مما يسمح بعرض شريط تقدم في واجهة المستخدم.
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
'/path/to/photo.jpg',
filename: 'photo.jpg',
),
'description': 'Profile photo',
})
await dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
final progress = sent / total * 100
print('رفع: $progress%')
},
)
// تنزيل الملف
await dio.download(
'https://example.com/file.zip',
'/storage/emulated/0/Download/file.zip',
onReceiveProgress: (received, total) {
print('تنزيل: ${received / total * 100}%')
},
)
معالجة الأخطاء غير الصحيحة هي المشكلة الأكثر شيوعًا. يطرح Dio DioException (المعروفة سابقًا بـ DioError) لأي مشاكل: انقطاع الشبكة أو المهلة أو أخطاء HTTP 4xx/5xx. يلتقط العديد من المطورين Exception العامة فقط، مما يفقد معلومات عن نوع الخطأ وإمكانية معالجته بشكل خاص. استخدم DioException.type لتحديد سبب الفشل.
تجاهل CancelToken يؤدي إلى تسرب الطلبات. إذا غادر المستخدم شاشة أثناء استمرار تنفيذ طلب، يهدر Dio الموارد وقد يحاول تحديث State مدمر. أنشئ دائمًا CancelToken لكل طلب وألغه في dispose(). يولد CancelToken DioException من نوع cancel، والتي يجب معالجتها بشكل صحيح.
عدم وجود منطق إعادة محاولة للأعطال المؤقتة. على الأجهزة المحمولة، غالبًا ما تكون الشبكة غير متاحة لفترة قصيرة. نفذ معترضًا مع إعادة محاولة تلقائية للطلب عند المهلة أو استجابة 503/502. استخدم RetryInterceptor من حزمة dio_smart_retry أو اكتب معترضًا مخصصًا مع تأخير أسي بين المحاولات.
الأسئلة الشائعة
Dio يوفر معترضات وتكوين BaseOptions عام و FormData وتقدم التحميل و CancelToken. حزمة http من فريق Dart بسيطة دون معترضات أو تكوين عام. يُستخدم Dio في المشاريع الكبيرة، بينما يُستخدم http في البرامج النصية البسيطة.
افتراضيًا، يحول Dio JSON إلى Map باستخدام jsonDecode. للتسلسل المنمط، استخدم حزم json_serializable أو freezed. أنشئ معترضًا مخصصًا يحول response.data إلى DTO عبر fromJson() في onResponse.
أنشئ CancelToken وقم بتمريره في خيارات الطلب. استدعاء token.cancel() يقطع الطلب ويطرح DioException من نوع cancel. يدعم CancelToken إلغاء طلبات متعددة في وقت واحد، وهو مناسب لإلغاء جميع الطلبات عند مغادرة الشاشة.
نعم، يعمل Dio على جميع منصات Flutter الست: Android و iOS و Web و macOS و Windows و Linux. كل منصة تستخدم عميل HTTP متكيف: DartNativeAdapter (المنصات الأصلية) و BrowserAdapter (Web). واجهة برمجة تطبيقات موحدة لجميع المنصات هي ميزة رئيسية لـ Dio في مشاريع Flutter.
لا يدير Dio الكوكيز تلقائيًا. لدعم الكوكيز، استخدم حزمة dio_cookie_manager مع cookie_jar. يعترض CookieManager رؤوس Set-Cookie و Cookie ويحفظ الكوكيز في PersistCookieJar لإرسالها تلقائيًا في الطلبات اللاحقة لنفس النطاق.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.