الشبكات وتكامل REST API

أساسيات HTTP وحزمة http

15 دقيقة الدرس 1 من 13

أساسيات HTTP وحزمة http

تتواصل كل تطبيقات Flutter العملية تقريباً مع خادم بعيد: جلب ملفات المستخدمين، تحميل كتالوجات المنتجات، إرسال بيانات النماذج، أو بث التحديثات المباشرة. كل هذا يحدث عبر HTTP (بروتوكول نقل النص التشعبي) — أساس تبادل البيانات على الويب. قبل كتابة أي سطر من كود Dart للشبكة، تحتاج إلى نموذج ذهني راسخ حول كيفية عمل HTTP.

دورة الطلب والاستجابة

كل تفاعل HTTP يتبع نفس النمط: يرسل العميل (تطبيق Flutter) طلباً إلى الخادم، ويرد الخادم بـ استجابة. تحمل كل رسالة جزأين:

  • الترويسات (Headers) — بيانات وصفية حول الرسالة (نوع المحتوى، رمز التفويض، توجيهات التخزين المؤقت، الترميزات المقبولة، إلخ)
  • الجسم (Body) — البيانات الفعلية (JSON أو HTML أو بيانات ثنائية أو فارغ)

طلب GET نموذجي إلى واجهة برمجة تطبيقات REST يبدو هكذا على مستوى البروتوكول:

طلب HTTP خام والاستجابة (مفاهيمي)

// الطلب (العميل → الخادم)
GET /users/42 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGci...

// الاستجابة (الخادم → العميل)
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87

{"id":42,"name":"Edrees","email":"edrees@example.com","role":"admin"}

طرق HTTP

يحدد HTTP عدة طرق طلب (تسمى أيضاً الأفعال) تُوصل النية إلى الخادم:

  • GET — استرجاع مورد؛ لا جسم؛ آمن ومتسق
  • POST — إنشاء مورد جديد أو إرسال بيانات؛ له جسم؛ غير متسق
  • PUT — استبدال مورد بالكامل؛ متسق
  • PATCH — تحديث جزئي لمورد
  • DELETE — حذف مورد

رموز الحالة

يرد الخادم دائماً بـ رمز حالة مكوّن من ثلاثة أرقام يخبرك ما إذا نجح الطلب ولماذا قد يكون فشل. يجب أن يعرف كل مطور Flutter النطاقات الرئيسية:

  • 2xx نجاح200 OK، 201 Created، 204 No Content
  • 3xx إعادة توجيه301 Moved Permanently، 304 Not Modified
  • 4xx خطأ العميل400 Bad Request، 401 Unauthorized، 403 Forbidden، 404 Not Found، 422 Unprocessable Entity
  • 5xx خطأ الخادم500 Internal Server Error، 503 Service Unavailable
ملاحظة: رمز الحالة 2xx يعني أن نقل HTTP نجح. هذا لا يعني أن منطق أعمالك نجح. دائماً حلّل جسم الاستجابة وتحقق من أي حقول "status" أو "error" تعيدها واجهة برمجة التطبيقات الخاصة بك.

إضافة حزمة http إلى Flutter

مكتبة Dart القياسية لا تحتوي على عميل HTTP مدمج مناسب لتطبيقات Flutter. الحل الرسمي هو حزمة http، التي يديرها فريق Dart. أضفها إلى مشروعك بأمر واحد:

إضافة الاعتمادية

// الطرفية — شغّل في جذر مشروعك:
flutter pub add http

// هذا يضيف السطر التالي إلى pubspec.yaml:
// dependencies:
//   http: ^1.2.1

// ثم استورده في أي ملف Dart:
import 'package:http/http.dart' as http;

الاسم المستعار as http هو اتفاقية المجتمع. يمنع تعارض الأسماء ويجعل كل موقع استدعاء واضحاً — http.get()، http.post()، إلخ.

أذونات الشبكة على Android وiOS

على المنصات المحمولة يفرض نظام التشغيل قواعد أمان الشبكة على مستوى النظام، وليس فقط في الكود:

  • Android — أضف <uses-permission android:name="android.permission.INTERNET" /> إلى android/app/src/main/AndroidManifest.xml. معظم قوالب Flutter تضمّنه تلقائياً.
  • iOS — يحجب أمان نقل التطبيق (ATS) بروتوكول HTTP العادي افتراضياً. التزم بـ https:// في الإنتاج؛ للتطوير المحلي فقط يمكنك إضافة استثناء ATS في ios/Runner/Info.plist.
تحذير: نسيان إذن INTERNET على Android هو السبب الأكثر شيوعاً لفشل تطبيق Flutter بصمت في إجراء استدعاءات الشبكة على جهاز حقيقي بينما يبدو أنه يعمل في المحاكي. تحقق دائماً من وجوده قبل مواصلة التصحيح.

إجراء أول طلب GET

تعيد الدالة http.get() كائناً من نوع Future<http.Response>. استخدم async/await للحفاظ على وضوح الكود. تحقق دائماً من response.statusCode قبل التعامل مع response.body.

أول طلب GET — جلب مستخدم

import 'dart:convert';
import 'package:http/http.dart' as http;

Future<Map<String, dynamic>> fetchUser(int id) async {
  final uri = Uri.parse('https://jsonplaceholder.typicode.com/users/$id');

  final response = await http.get(
    uri,
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN',
    },
  );

  if (response.statusCode == 200) {
    // response.body هو String خام؛ حوّله إلى Map
    return jsonDecode(response.body) as Map<String, dynamic>;
  } else {
    throw Exception(
      'فشل في جلب المستخدم. الحالة: ${response.statusCode}',
    );
  }
}

فهم كائن الاستجابة

يعرض كائن http.Response الذي تعيده كل استدعاء هذه الخصائص الرئيسية:

  • statusCode — عدد صحيح (مثل 200)
  • body — جسم الاستجابة الخام كـ String بترميز UTF-8
  • bodyBytes — الجسم كـ Uint8List (للبيانات الثنائية)
  • headersMap<String, String> من ترويسات الاستجابة
  • reasonPhrase — نص حالة يمكن قراءته بشرياً (مثل "OK")
نصيحة: استخدم Uri.parse() أو منشئات Uri.https() / Uri.http() بدلاً من تمرير سلاسل نصية خام. تتعامل متغيرات المنشئ تلقائياً مع ترميز URL لمعاملات الاستعلام، مما يمنع أخطاء الترميز الصعبة التصحيح عندما تحتوي القيم على مسافات أو أحرف خاصة.

ملخص

في هذا الدرس تعلمت أن HTTP هو بروتوكول طلب/استجابة حيث يرسل العميل فعلاً (GET، POST...) مع ترويسات وجسم اختياري، ويرد الخادم برمز حالة وجسم. أضفت حزمة http عبر flutter pub add http، استوردتها بالاسم المستعار القياسي as http، وكتبت أول طلب GET غير متزامن يتحقق من رمز الحالة ويحلل جسم JSON. في الدرس التالي ستصمم JSON كفئات Dart مكتوبة باستخدام نمط model / fromJson.