Node.js / المتوسط: حدود التطبيق / الدرس 7
عقود الواجهات والتحقق من المدخلات
حدد حدود واجهة صغيرة تميز صياغة النقل والتحقق من البيانات وقواعد المجال قبل تغيير الحالة.
في هذه الصفحة
أهداف الدرس
- اشرح المفاهيم والمفاضلات المتعلقة بموضوع «عقود الواجهات والتحقق من المدخلات».
- توقع المثالين وتحقق من مخرجاتهما وسلوك تنظيف الموارد فيهما.
- شخّص الإخفاقات الثلاثة الشائعة وطبق الحلول المشروحة على مدخلات مشابهة.
العقد أوسع من مسار
يحدد عقد الواجهة الطرق والمسارات والترويسات وأنواع الحقول والحدود ومعاني الاستجابات. قرر رفض الحقول المجهولة والفرق بين الغياب وnull. لا يعني كائن JSON الصحيح أمرا صحيحا للعمل. افصل فك النقل عن التحقق وعن عملية المجال. يسمح هذا الترتيب برفض الطلب قبل تخصيص موارد مكلفة أو تعديل البيانات. وثّق أمثلة للقبول والرفض كي لا يستنتج العميل العقد من تفاصيل تنفيذ عرضية.
تقييد المدخلات قبل الاحتفاظ بها
تصل بيانات الشبكة في مقاطع لا تطابق حدود رموز JSON. يجب أن يعد القارئ الفعلي البايتات أثناء وصولها ويفرض حدا وحساب مهلة وسياسة للبيانات غير المقروءة. Content-Length إشارة مبكرة وليست كافية لكل أنماط النقل. فك النص بعد استيفاء حد البايتات ثم حلله وتحقق منه. يبدأ المثال الأول من Buffer محدود مسبقا لعرض المراحل اللاحقة؛ وتبقى مسؤولية تقييد الاستقبال الشبكي على المستدعي.
التحقق البنيوي دون تحويل خفي
يقبل المحلل كائنا غير مصفوفة بحقل name واحد. يفحص ميزانية البايتات قبل التحليل، ويرفض الحقول المجهولة ويزيل الفراغ المحيط بالاسم ويتحقق من طوله. يبقى الحقل النصي نصا حتى إن بدا رقما ما لم يسمح العقد بالتحويل. أعد كائنا جديدا متحققا منه بدلا من تمرير خصائص المستخدم كلها، حتى لا تتحول حقول مفاجئة إلى سمات تخزين أو أذونات. يجب أن توضح الرسالة التصحيح الممكن دون كشف تفاصيل التنفيذ أو المسارات أو الاعتمادات.
function parseCreate(bytes) {
if (bytes.length > 128) throw new Error('413 body too large');
let value;
try { value = JSON.parse(bytes.toString('utf8')); }
catch { throw new Error('400 malformed JSON'); }
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('422 expected object');
if (Object.keys(value).some(key => key !== 'name')) throw new Error('422 unknown field');
if (typeof value.name !== 'string' || value.name.trim().length < 1 || value.name.trim().length > 40) throw new Error('422 invalid name');
return { name: value.name.trim() };
}
console.log(JSON.stringify(parseCreate(Buffer.from('{"name":" Ada "}'))));
try { parseCreate(Buffer.from('{"name":"Ada","admin":true}')); }
catch (error) { console.log(error.message); }
{"name":"Ada"}
422 unknown field
لا يعبر الحد إلا الحقل المسموح بعد تطبيعه. يستقبل المحلل مخزنا مكتملا محدودا، ولا يجمع جسم الطلب من الشبكة.
اختيار معاني HTTP مستقرة
استخدم 400 لصياغة الطلب المشوهة، و413 للجسم المتجاوز للحد، و415 لنوع الوسائط غير المدعوم. يمكن اعتماد 422 لأوامر فُكت بنيتها لكنها غير صالحة إذا وُثّق ذلك باتساق. وللتحقق من الهوية والصلاحية معنيان مستقلان، وقد تخفي سياسة عدم العثور موردا محميا عمدا. يتحقق المثال الثاني من معامل limit بصيغة عشرية دقيقة ومدى محدد، ويعيد كائن خطأ مستقرا بدلا من تسريب استثناءات المحلل إلى استجابات عشوائية.
function pageLimit(target) {
const url = new URL(target, 'http://local');
const values = url.searchParams.getAll('limit');
if (values.length === 0) return { limit: 20 };
if (values.length !== 1 || !/^\d+$/.test(values[0])) return { error: 'invalid_limit' };
const limit = Number(values[0]);
return Number.isInteger(limit) && limit >= 1 && limit <= 100 ? { limit } : { error: 'invalid_limit' };
}
console.log(JSON.stringify(pageLimit('/items?limit=25')));
console.log(JSON.stringify(pageLimit('/items?limit=1&limit=2')));
{"limit":25}
{"error":"invalid_limit"}
تُرفض المعاملات المكررة عمدا لمنع اختلاف تفسير الوكيل والتطبيق.
حماية عمليات تغيير الحالة
لا يحل التحقق محل الصلاحيات أو المعاملات أو منع تكرار الأثر. قد يتجاوز مبلغ صحيح الرصيد، وقد يخص معرف صحيح مستخدما آخر. طبّق قواعد المجال قرب تغيير الحالة كي لا تبطل الطلبات المتزامنة قرارا سابقا. عرّف مفتاحا لمنع تكرار الأثر في عمليات الإنشاء القابلة لإعادة المحاولة، واربطه بالمستدعي والعمل المقصود. خزّن المفتاح والنتيجة مع التغيير عندما تلزم الذرية. يساعد العقد المتسق العميل على إعادة المحاولة بأمان ويمنح الاختبارات سلوكا قابلا للملاحظة.
الأخطاء الشائعة وإصلاحها
قبول نص عددي في مخطط عدد صحيح
- لماذا يحدث؟
- حل التحويل الضمني محل التحقق.
- كيف تصلحه؟
- اطلب النوع الموثق أو وثّق التحويل صراحة.
- كيف تتجنب تكراره؟
- أضف حالات النوع الخاطئ إلى اختبارات العقد.
تنمو الذاكرة قبل استجابة 413
- لماذا يحدث؟
- جُمّع الجسم كاملا قبل فحص حجمه.
- كيف تصلحه؟
- افرض الحد أثناء الاستقبال وتوقف عن الاحتفاظ بالبيانات الزائدة.
- كيف تتجنب تكراره؟
- اختبر الأجسام المجزأة الكبيرة والمهل.
يضبط العميل خاصية admin
- لماذا يحدث؟
- نُسخت كل الحقول المفكوكة إلى نموذج موثوق.
- كيف تصلحه؟
- ابن كائن أمر من الحقول المسموحة فقط.
- كيف تتجنب تكراره؟
- أبعد قرارات الامتيازات عن الحقول الخاضعة للمستخدم.
اختبر فهمك
1. صنف JSON مشوهة وجسما كبيرا وكائنا صحيح الصياغة ينقصه الاسم المطلوب.
اعرض الحل المشروح
تصبح وفق عقد الدرس 400 و413 و422 على الترتيب. افحص حد البايتات أولا ثم حلل الصياغة ثم تحقق من الحقول. ستصنف 500 عامة إخفاقات يستطيع العميل تصحيحها تصنيفا خاطئا وتحجب معلومات المراقبة.
2. يحمل تحديث صحيح معرف مورد يخص مستخدما آخر. ما الفحص الإضافي؟
اعرض الحل المشروح
تحقق من صلاحية الفاعل الموثق للمورد والعملية قبل تغيير الحالة. يثبت التحقق شكل المعرف فقط. نفذ فحص الملكية ضمن القرار المعاملي نفسه مع التحديث عندما يمكن أن تتغير الملكية بالتزامن.
أهم ما تعلمته
- يحدد عقد الواجهة الطرق والمسارات والترويسات وأنواع الحقول والحدود ومعاني الاستجابات.
- تصل بيانات الشبكة في مقاطع لا تطابق حدود رموز JSON.
- لا يحل التحقق محل الصلاحيات أو المعاملات أو منع تكرار الأثر.