Kodokon kodokon.com

التحقق من المُدخلات والبرمجية الوسيطة للأخطاء

تحقّق من البيانات عند حدود واجهة برمجة التطبيقات (API) ومركِز معالجة الأخطاء كلها في برمجية وسيطة واحدة ذات أربعة وسائط.

9 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

كل بيانات واردة عدائية حتى يثبت العكس: جسم JSON، ومعاملات URL، والترويسات (headers). ينتمي التحقق إلى حدود التطبيق - قبل المتحكم - حتى تعمل الطبقات الداخلية على بيانات مضمونة. ثم ميّز بين عائلتين من الأخطاء: الأخطاء التشغيلية (مُدخَل غير صالح، أو مورد مفقود، أو تعارض)، وهي متوقعة وتُترجَم إلى 4xx، وأخطاء البرمجة (العلل bugs)، التي يجب أن تُنتِج خطأ 500 مبهمًا في جانب العميل وتتبُّعًا كاملًا للمكدس في جانب الخادم.

JAVASCRIPT
export class HttpError extends Error {
  constructor(status, message, details = undefined) {
    super(message);
    this.status = status;
    this.details = details;
  }
}
خطأ يحمل رمز حالته في HTTP: اللبنة الأساسية.

تعترض برمجية وسيطة للتحقق الطلبَ قبل المتحكم. تُظهِر النسخة اليدوية أدناه المبدأ؛ وفي بيئة الإنتاج، يوفّر مخطط تصريحي (أصبح zod هو المعيار) إضافةً إلى ذلك استنتاج الأنواع ورسائل منظّمة. والمقايضة: تبعية واحدة وتكلفة طفيفة أثناء التشغيل، مقابل قواعد مركزية قابلة للتركيب يستحيل نسيانها.

JAVASCRIPT
import { HttpError } from './http-error.js';

export function validateUser(req, res, next) {
  const { email, name } = req.body ?? {};
  const errors = [];
  if (typeof email !== 'string' || !email.includes('@')) {
    errors.push('email: invalid format');
  }
  if (typeof name !== 'string' || name.trim().length < 2) {
    errors.push('name: 2 characters minimum');
  }
  if (errors.length > 0) {
    return next(new HttpError(400, 'Invalid body', errors));
  }
  next();
}
اربطها باستخدام router.post('/', validateUser, controller.create).

يتعرّف Express على برمجية وسيطة للأخطاء من خلال توقيعها ذي الأربعة وسائط (err, req, res, next). وإذ تُسجَّل أخيرًا، بعد كل المسارات باستخدام app.use(errorHandler)، تصبح مخرج الأخطاء الوحيد لواجهة برمجة التطبيقات (API): تنسيق استجابة متجانس، وتسجيل في مكان واحد، ودون تسريب أيّ معلومات داخلية. أما المتحكمات، من جهتها، فتكتفي باستدعاء next(err).

JAVASCRIPT
export function errorHandler(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }
  const status = err.status ?? 500;
  const body = { error: err.message };
  if (err.details) {
    body.details = err.details;
  }
  if (status >= 500) {
    console.error(err);
    body.error = 'Internal server error';
  }
  res.status(status).json(body);
}
أخطاء 4xx شفافة للعميل، وأخطاء 500 مُخفاة لكنها مُسجَّلة.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. كيف يميّز Express برمجية وسيطة للأخطاء عن أخرى عادية؟
    • من خلال اسمها، الذي يجب أن يحتوي على كلمة error
    • من خلال توقيعها ذي الأربعة وسائط (err, req, res, next)
    • من خلال موضعها الأول في السلسلة
    • من خلال استدعاء صريح لـ app.setErrorHandler
  2. ما الاستجابة الصحيحة في HTTP لخطأ برمجة غير متوقع؟
    • خطأ 500 مع الرسالة والمكدس للمساعدة في التشخيص
    • خطأ 400 للإشارة إلى فشل الطلب
    • خطأ 500 برسالة عامة، مع تسجيل الخطأ الكامل في جانب الخادم
  3. في Express 4، ماذا يحدث إذا رُفِض مُعالِج غير متزامن دون try/catch؟
    • يصل الخطأ إلى برمجية الأخطاء الوسيطة رغم ذلك
    • يبقى الطلب معلّقًا: لا يُمرَّر الرفض أبدًا إلى next
    • يُرجِع Express خطأ 400 تلقائيًا
    • تتوقف عملية Node فورًا