كيف تصمم ترقيم الصفحات في واجهة برمجة التطبيقات (API) لملايين السجلات؟

Ashley Innocent

Ashley Innocent

13 مارس 2026

كيف تصمم ترقيم الصفحات في واجهة برمجة التطبيقات (API) لملايين السجلات؟

enterprise.banner.title

enterprise.banner.feature1

enterprise.banner.feature2

enterprise.banner.feature3

enterprise.banner.ctaB

خلاصة

بالنسبة لمجموعات البيانات الكبيرة، استخدم ترقيم الصفحات المعتمد على المؤشر (cursor-based) أو المعتمد على المفاتيح (keyset) بدلاً من ترقيم الصفحات المعتمد على الإزاحة (offset-based). ترقيم الصفحات بالإزاحة (?page=1&limit=20) يؤدي أداءً سيئًا مع ملايين السجلات ويسمح بعدم اتساق البيانات. تطبق PetstoreAPI الحديثة ترقيم الصفحات المعتمد على المؤشر باستخدام رموز غير شفافة وروابط HATEOAS للحصول على نتائج فعالة ومتسقة.

مقدمة

تقوم واجهة برمجة التطبيقات (API) الخاصة بك بإرجاع قائمة من الحيوانات الأليفة. لديك 10 ملايين حيوان أليف في قاعدة البيانات. يطلب العميل GET /pets?page=500000&limit=20. تنفذ قاعدة البيانات الخاصة بك الأمر OFFSET 10000000 LIMIT 20. يستغرق الاستعلام 30 ثانية. تنتهي مهلة واجهة برمجة التطبيقات الخاصة بك.

هذه هي مشكلة ترقيم الصفحات بالإزاحة. إنها تعمل بشكل جيد لمجموعات البيانات الصغيرة ولكنها تتعطل عند التوسع. يجب على قاعدة البيانات مسح ملايين الصفوف للوصول إلى الإزاحة، على الرغم من أنك ترجع 20 نتيجة فقط.

Swagger Petstore القديم لا يتناول ترقيم الصفحات على الإطلاق. Modern PetstoreAPI يطبق ترقيم الصفحات المعتمد على المؤشر والذي يتوسع إلى ملايين السجلات بأداء ثابت.

💡
إذا كنت تقوم بإنشاء أو اختبار واجهات برمجة تطبيقات REST، فإن Apidog يساعدك على اختبار سلوك ترقيم الصفحات، والتحقق من تنسيقات الاستجابة، والتأكد من أن واجهة برمجة التطبيقات الخاصة بك تتعامل مع مجموعات البيانات الكبيرة بشكل صحيح. يمكنك محاكاة سيناريوهات ترقيم الصفحات، واختبار الحالات الهامشية، والتحقق من الأداء.
زر

في هذا الدليل، ستتعلم لماذا يفشل ترقيم الصفحات بالإزاحة، وكيف يعمل ترقيم الصفحات المعتمد على المؤشر، وكيف تطبق Modern PetstoreAPI ترقيم الصفحات الفعال.

لماذا يفشل ترقيم الصفحات بالإزاحة عند التوسع

ترقيم الصفحات بالإزاحة هو النهج الأكثر شيوعًا، ولكنه يعاني من مشاكل خطيرة.

كيف يعمل ترقيم الصفحات بالإزاحة

GET /pets?page=1&limit=20    ← OFFSET 0 LIMIT 20
GET /pets?page=2&limit=20    ← OFFSET 20 LIMIT 20
GET /pets?page=3&limit=20    ← OFFSET 40 LIMIT 20

تتخطى قاعدة البيانات offset من الصفوف وتُرجع limit من الصفوف.

المشكلة 1: تدهور الأداء مع رقم الصفحة

الصفحة 1:

SELECT * FROM pets OFFSET 0 LIMIT 20;
-- سريع: يمسح 20 صفًا

الصفحة 1000:

SELECT * FROM pets OFFSET 20000 LIMIT 20;
-- بطيء: يمسح 20,020 صفًا، ويعيد 20

الصفحة 500,000:

SELECT * FROM pets OFFSET 10000000 LIMIT 20;
-- بطيء جدًا: يمسح 10,000,020 صفًا، ويعيد 20

يجب على قاعدة البيانات مسح جميع الصفوف حتى الإزاحة، على الرغم من أنها تتجاهلها. يتدهور الأداء خطيًا مع رقم الصفحة.

المشكلة 2: نتائج غير متناسقة

بينما يتصفح العميل النتائج، تتغير البيانات:

الطلب 1:

GET /pets?page=1&limit=2
الإرجاع: [الحيوان الأليف أ، الحيوان الأليف ب]

شخص يضيف الحيوان الأليف Z (يتم فرزه أولاً أبجديًا)

الطلب 2:

GET /pets?page=2&limit=2
الإرجاع: [الحيوان الأليف ب، الحيوان الأليف ج]  ← الحيوان الأليف ب يظهر مرتين!

ظهر الحيوان الأليف B في كلتا الصفحتين بسبب إدخال حيوان أليف جديد. على العكس من ذلك، يمكن تخطي الحيوانات الأليفة إذا حدثت عمليات حذف.

المشكلة 3: ترقيم الصفحات العميق مكلف

نادرًا ما يتجاوز المستخدمون الصفحة 10. ولكن إذا كانت واجهة برمجة التطبيقات الخاصة بك تسمح بـ ?page=1000000، فيجب عليك التعامل معها. استعلامات ترقيم الصفحات العميقة مكلفة ويمكن استخدامها لهجمات حجب الخدمة.

متى يكون ترقيم الصفحات بالإزاحة مقبولاً

يعمل ترقيم الصفحات بالإزاحة بشكل جيد لـ:

بالنسبة لواجهات برمجة التطبيقات العامة أو مجموعات البيانات الكبيرة، استخدم ترقيم الصفحات المعتمد على المؤشر.

شرح ترقيم الصفحات المعتمد على المؤشر

يستخدم ترقيم الصفحات المعتمد على المؤشر رمزًا غير شفاف لتحديد الموضع في مجموعة النتائج.

كيف يعمل

الطلب 1:

GET /pets?limit=20

الاستجابة 1:

{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6IjAxOWI0MTMyLTcwYWEtNzY0Zi1iMzE1LWUyODAzZDg4MmEyNCJ9",
    "hasMore": true
  }
}

الطلب 2:

GET /pets?cursor=eyJpZCI6IjAxOWI0MTMyLTcwYWEtNzY0Zi1iMzE1LWUyODAzZDg4MmEyNCJ9&limit=20

المؤشر هو رمز غير شفاف (عادةً ما يكون مشفرًا بـ base64) يقوم بتشفير الموضع. لا يقوم العميل بتحليله – فقط يمرره مرة أخرى.

المزايا

1. أداء ثابت

تستخدم قاعدة البيانات فهرسًا للعثور على موضع المؤشر مباشرةً:

SELECT * FROM pets
WHERE id > '019b4132-70aa-764f-b315-e2803d882a24'
ORDER BY id
LIMIT 20;

هذا الاستعلام سريع بغض النظر عن الموضع في مجموعة البيانات. يستخدم بحث فهرس، وليس مسحًا.

2. نتائج متناسقة

المؤشرات مستقرة. إذا تغيرت البيانات بين الطلبات، فإنك لا تزال تحصل على نتائج متناسقة. السجلات الجديدة لا تسبب تكرارًا أو تخطيًا.

3. لا توجد هجمات ترقيم صفحات عميقة

لا يمكن للعملاء الانتقال إلى مواضع عشوائية. يجب عليهم التصفح تسلسليًا، مما يحد من سوء الاستخدام.

تنسيق المؤشر

عادةً ما تكون المؤشرات بتنسيق JSON مشفر بـ base64:

// مؤشر مفكك التشفير
{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "createdAt": "2026-03-13T10:30:00Z"
}

يحتوي المؤشر على معلومات كافية لاستئناف ترقيم الصفحات. بالنسبة لـ Modern PetstoreAPI، يشمل ذلك معرف المورد وحقل الفرز.

ترقيم الصفحات بالمفاتيح للبيانات المصنفة

ترقيم الصفحات بالمفاتيح هو نوع من ترقيم الصفحات المعتمد على المؤشر للبيانات المصنفة.

كيف يعمل

بدلاً من المؤشر غير الشفاف، تستخدم القيمة الأخيرة من الصفحة السابقة:

الطلب 1:

GET /pets?limit=20&sortBy=createdAt

الاستجابة 1:

{
  "data": [
    {"id": "...", "createdAt": "2026-03-13T10:00:00Z"},
    ...
    {"id": "...", "createdAt": "2026-03-13T10:30:00Z"}
  ]
}

الطلب 2:

GET /pets?limit=20&sortBy=createdAt&after=2026-03-13T10:30:00Z

تستخدم المعلمة after القيمة الأخيرة لـ createdAt من الصفحة السابقة.

استعلام SQL

SELECT * FROM pets
WHERE created_at > '2026-03-13T10:30:00Z'
ORDER BY created_at
LIMIT 20;

هذا فعال لأنه يستخدم فهرسًا على created_at.

متى تستخدم ترقيم الصفحات بالمفاتيح

Modern PetstoreAPI تستخدم ترقيم الصفحات المعتمد على المؤشر بشكل افتراضي ولكنها تدعم ترقيم الصفحات بالمفاتيح لبيانات السلاسل الزمنية.

كيف تطبق Modern PetstoreAPI ترقيم الصفحات

تستخدم Modern PetstoreAPI ترقيم الصفحات المعتمد على المؤشر مع روابط HATEOAS.

تنسيق الطلب

GET /pets?limit=20
GET /pets?cursor={token}&limit=20

المعلمات:

تنسيق الاستجابة

{
  "data": [
    {
      "id": "019b4132-70aa-764f-b315-e2803d882a24",
      "name": "Fluffy",
      "species": "CAT"
    }
  ],
  "pagination": {
    "limit": 20,
    "hasMore": true,
    "nextCursor": "eyJpZCI6IjAxOWI0MTMyLTcwYWEtNzY0Zi1iMzE1LWUyODAzZDg4MmEyNCJ9"
  },
  "links": {
    "self": "https://petstoreapi.com/pets?limit=20",
    "next": "https://petstoreapi.com/pets?cursor=eyJpZCI6IjAxOWI0MTMyLTcwYWEtNzY0Zi1iMzE1LWUyODAzZDg4MmEyNCJ9&limit=20"
  }
}

الميزات الرئيسية

1. المؤشرات غير الشفافة

المؤشرات مشفرة بـ base64. لا يقوم العملاء بتحليلها.

2. روابط HATEOAS

كائن links يوفر عناوين URL جاهزة للاستخدام. لا يحتاج العملاء إلى بناء عناوين URL لترقيم الصفحات.

3. علامة hasMore

تشير إلى ما إذا كانت هناك المزيد من النتائج. يعرف العملاء متى يتوقفون عن التصفح.

4. التحقق من صحة الحد الأقصى

الحد الأقصى هو 100. يمنع العملاء من طلب صفحات ضخمة.

راجع وثائق ترقيم الصفحات في Modern PetstoreAPI للحصول على تفاصيل كاملة.

تنسيق استجابة ترقيم الصفحات

تغلف Modern PetstoreAPI استجابات ترقيم الصفحات في هيكل متسق.

غلاف المجموعة

{
  "data": [...],
  "pagination": {...},
  "links": {...}
}

لماذا تُغلف المجموعات؟

  1. القابلية للتوسع - يمكن إضافة بيانات وصفية دون تعطيل العملاء
  2. الاتساق - جميع نقاط نهاية ترقيم الصفحات تستخدم نفس التنسيق
  3. HATEOAS - توجه الروابط العملاء خلال ترقيم الصفحات

البيانات الوصفية لترقيم الصفحات

"pagination": {
  "limit": 20,
  "hasMore": true,
  "nextCursor": "...",
  "totalCount": 1000  // اختياري، مكلف للحساب
}

totalCount اختياري لأن حسابه مكلف لمجموعات البيانات الكبيرة. معظم العملاء لا يحتاجون إليه.

اختبار ترقيم الصفحات باستخدام Apidog

Apidog يساعدك على اختبار سلوك ترقيم الصفحات بشكل شامل.

سيناريوهات الاختبار

1. الصفحة الأولى

GET /pets?limit=20
النتيجة المتوقعة: 20 نتيجة، hasMore=true، nextCursor موجود

2. الصفحات التالية

GET /pets?cursor={token}&limit=20
النتيجة المتوقعة: 20 نتيجة، hasMore=true/false، nextCursor موجود/غائب

3. الصفحة الأخيرة

GET /pets?cursor={lastToken}&limit=20
النتيجة المتوقعة: < 20 نتيجة، hasMore=false، لا يوجد nextCursor

4. نتائج فارغة

GET /pets?status=NONEXISTENT&limit=20
النتيجة المتوقعة: 0 نتائج، hasMore=false، لا يوجد nextCursor

5. التحقق من صحة الحد الأقصى

GET /pets?limit=1000
النتيجة المتوقعة: 400 طلب سيء (يتجاوز الحد الأقصى)

إعداد اختبار Apidog

// Test: Pagination structure
pm.test("Response has pagination", () => {
  pm.expect(pm.response.json()).to.have.property('pagination');
  pm.expect(pm.response.json().pagination).to.have.property('hasMore');
});

// Test: HATEOAS links
pm.test("Response has links", () => {
  const links = pm.response.json().links;
  pm.expect(links).to.have.property('self');
  if (pm.response.json().pagination.hasMore) {
    pm.expect(links).to.have.property('next');
  }
});

اختيار استراتيجية ترقيم الصفحات الصحيحة

تتناسب الاستراتيجيات المختلفة مع حالات الاستخدام المختلفة.

ترقيم الصفحات بالإزاحة

استخدم عندما:

لا تستخدم عندما:

ترقيم الصفحات المعتمد على المؤشر

استخدم عندما:

لا تستخدم عندما:

ترقيم الصفحات بالمفاتيح

استخدم عندما:

لا تستخدم عندما:

توصية Modern PetstoreAPI: استخدم ترقيم الصفحات المعتمد على المؤشر لواجهات برمجة التطبيقات العامة ومجموعات البيانات الكبيرة.

الخلاصة

ترقيم الصفحات أمر بالغ الأهمية لواجهات برمجة التطبيقات التي تُرجع مجموعات بيانات كبيرة. ترقيم الصفحات بالإزاحة بسيط ولكنه لا يتوسع. يوفر ترقيم الصفحات المعتمد على المؤشر أداءً ثابتًا ونتائج موثوقة لملايين السجلات.

Modern PetstoreAPI تطبق ترقيم الصفحات المعتمد على المؤشر برموز غير شفافة، وروابط HATEOAS، وبيانات وصفية مناسبة. هذا التصميم يتوسع بكفاءة ويوفر تجربة مطور رائعة.

اختبر تنفيذ ترقيم الصفحات الخاص بك باستخدام Apidog للتأكد من أنه يتعامل مع الحالات الهامشية، ويتحقق من الحدود، ويعيد نتائج متسقة.

النقاط الرئيسية:

زر

الأسئلة الشائعة

لماذا لا يتم إرجاع جميع النتائج دون ترقيم الصفحات؟

إرجاع ملايين السجلات في استجابة واحدة يسبب مشاكل في الذاكرة، وبطء نقل الشبكة، وتجربة مستخدم سيئة. ترقيم الصفحات ضروري لمجموعات البيانات الكبيرة.

هل يمكن للعملاء القفز إلى صفحة معينة باستخدام ترقيم الصفحات بالمؤشر؟

لا، يتطلب ترقيم الصفحات بالمؤشر وصولاً تسلسليًا. إذا كان الوصول العشوائي مطلوبًا، ففكر في ترقيم الصفحات بالإزاحة لمجموعات البيانات الصغيرة أو قم بتطبيق البحث/التصفية بدلاً من ذلك.

كيف أتعامل مع ترقيم الصفحات مع التصفية؟

قم بتضمين معلمات التصفية في طلبات ترقيم الصفحات: GET /pets?status=AVAILABLE&cursor={token}&limit=20. يقوم المؤشر بتشفير كل من الموضع وحالة التصفية.

هل يجب أن أضمّن العدد الكلي في استجابات ترقيم الصفحات؟

فقط إذا كان العملاء يحتاجون إليه وكانت مجموعة البيانات الخاصة بك صغيرة. حساب العدد الكلي مكلف لمجموعات البيانات الكبيرة (يتطلب استعلام COUNT منفصلًا).

كيف أطبق ترقيم الصفحات بالمؤشر في SQL؟

استخدم عبارة WHERE مع قيمة المؤشر: SELECT * FROM pets WHERE id > ? ORDER BY id LIMIT 20. تأكد من وجود فهرس على عمود الفرز.

ماذا لو أصبحت رموز المؤشر الخاصة بي غير صالحة؟

أعد 400 Bad Request مع رسالة خطأ. يمكن أن تصبح المؤشرات غير صالحة إذا تم حذف البيانات أو انتهت صلاحية حالة ترقيم الصفحات.

إلى متى يجب أن تظل المؤشرات صالحة؟

تظل مؤشرات Modern PetstoreAPI صالحة إلى أجل غير مسمى طالما أن المورد المشار إليه موجود. بعض واجهات برمجة التطبيقات تنتهي صلاحية المؤشرات بعد 24 ساعة.

هل يمكنني استخدام ترقيم الصفحات بالمؤشر مع حقول فرز متعددة؟

نعم، ولكن يجب أن يقوم المؤشر بتشفير جميع حقول الفرز. هذا يجعل المؤشرات أكثر تعقيدًا. فكر في استخدام مفتاح فرز مركب واحد بدلاً من ذلك.

ممارسة تصميم API في Apidog

اكتشف طريقة أسهل لبناء واستخدام واجهات برمجة التطبيقات