معالجة الأخطاء (Error handling) في Nuxt

الحمد لله الذي علَّم بالقلم، علَّم الإنسان ما لم يعلم، والصلاة والسلام على خير معلِّم الناس الخير سيدنا محمد - صلَّى الله عليه وسلم … أما بعد ،،
في كل مشروع ويب نطوره، هناك لحظة لا مفر منها: عند حدوث خطأ ما.
قد يكون الخطأ ناتجًا عن مشكلة في الاتصال بالخادم، أو عن صفحة غير موجودة، أو حتى بسبب إدخال غير صحيح من المستخدم.
في هذا المقال، نستعرض كيف يوفّر Nuxt أدوات مرنة للتعامل مع الأخطاء بسلاسة، ونوضح كيف يمكنك أن تحوّل لحظات الفشل إلى فرص لبناء تجربة أكثر نضجًا وموثوقية.
معالجة الأخطاء مركزيا
بدلًا من التعامل مع كل خطأ يظهر في التطبيق بشكل منفصل، يمكنك إعداد طريقة واحدة تتولى متابعة جميع الطلبات التي يجريها التطبيق لجلب البيانات، وتراقب ما إذا حدث فيها خطأ.
هذه الطريقة تشبه الحارس الذي يقف على الباب ويتأكد أن كل شيء يسير بشكل سليم، وإذا وقع خطأ، يتصرف تلقائيًا: يُظهر رسالة مناسبة للمستخدم، أو يُعيد المحاولة، أو يُخبرك كمطور بوجود مشكلة.
هذا الأسلوب يجعل التطبيق أكثر تنظيمًا وراحة، ويقلّل من التكرار والأخطاء في الصفحات المختلفة.
// plugins/api.ts
import { showError } from '#app'
export default defineNuxtPlugin(nuxtApp => {
const config = useRuntimeConfig()
const api = $fetch.create({
baseURL: config.public.BASE_URL,
async onResponseError({ response }) {
if (response?._data?.error) {
await nuxtApp.runWithContext(() => {
showError({ statusCode: response?._data.statusCode })
})
}
},
})
return {
provide: {
api,
},
}
})
الكود السابق يُستخدم لتجهيز طريقة واحدة داخل التطبيق تقوم بإرسال الطلبات إلى موقع خارجي لجلب البيانات، وفي حال حدث خطأ أثناء ذلك، مثل أن يكون هناك خلل في الرد أو البيانات غير متوفرة، يعرض التطبيق تلقائيًا صفحة خطأ مناسبة بدلًا من أن يتوقف فجأة.
هذا الترتيب يُسهل عليك التعامل مع الأخطاء في مكان واحد دون الحاجة لتكرار نفس الخطوات في كل صفحة من صفحات الموقع.
// composables/useAPI.ts
import type { NitroFetchRequest } from 'nitropack'
export function useAPI<T = unknown>(
request: NitroFetchRequest | Ref<NitroFetchRequest> | (() => NitroFetchRequest),
opts: Parameters<typeof useFetch<T>>[1] = {},
) {
const nuxtApp = useNuxtApp()
const serverFetch = useRequestFetch()
const clientFetch = nuxtApp.$api as typeof $fetch
const $f = import.meta.server ? (serverFetch as typeof $fetch) : clientFetch
return useFetch<T>(request, {
...opts,
$fetch: $f,
})
}
الكود السابق يهدف لإنشاء طريقة موحّدة وآمنة لجلب البيانات داخل تطبيق Nuxt، بحيث يتم تحديد العنوان الرئيسي للواجهة البرمجية من إعدادات التطبيق، ثم إعداد نسخة مخصصة من أداة الجلب $fetch.
هذه النسخة تتميز بقدرتها على رصد الأخطاء تلقائيًا، والتصرف عند حدوثها من خلال عرض صفحة خطأ مناسبة للمستخدم دون التأثير على بقية تجربة التصفح.
في نهاية الكود، يتم توفير هذه الأداة تحت اسم api داخل التطبيق، مما يتيح استخدامها بسهولة في أي مكان دون الحاجة لتكرار الإعدادات أو كتابة معالجة الأخطاء من جديد، وهو ما يجعل الكود أنظف وأكثر تنظيمًا، كما يلي:
const { data, status } = await useAPI(`/api/admin/users`)
أو يمكنك استخدام api$ مباشرة كما يلي:
const isLoadingSend = ref(false)
const sendMessage = async () => {
const { $api } = useNuxtApp()
const body = {
message: message.value,
}
isLoadingSend.value = true
try {
await $api('/api/contacts', {
method: 'POST',
body,
})
await router.push('/')
show(`تم ارسل الرسالة بنجاح`, 'success')
} finally {
isLoadingSend.value = false
}
}
للمزيد حول هذا الجزء، يمكنك الرجوع للتوثيق الرسمي بالضغط هنا
صفحة خطأ مخصصة
في تطبيقات Nuxt، قد تظهر أخطاء غير متوقعة أثناء الاستخدام، وهنا تبرز أهمية وجود صفحة مخصصة لعرض الخطأ تُعرف باسم error.vue.
هذه الصفحة تتيح لك استبدال صفحة الخطأ الافتراضية بتصميم مناسب يعرض رسالة واضحة للمستخدم، مثل رقم الخطأ أو رابط للعودة إلى الصفحة الرئيسية، مما يحافظ على تجربة استخدام محترفة حتى في حالات الفشل.
رغم أنها تُسمى "صفحة خطأ"، إلا أنها ليست جزءًا من الصفحات العادية، ويجب وضعها خارج مجلد pages.
عند حدوث خطأ، يتم تمرير كائن error يحتوي على معلومات مهمة مثل رقم الحالة والرسالة، ويمكنك أيضًا تمرير معلومات إضافية ضمن خاصية data، لتتمكن من عرض ما يناسب المستخدم والتصرف بمرونة حسب نوع الخطأ.
فيما يلي مثال علي الكود الكامل لهذه الصفحة كالتالي:
// error.vue
<template>
<div style="min-height: 100vh">
<v-row class="pt-8 px-4">
<v-col cols="12" md="6" class="mx-auto">
<v-card class="mt-4 mt-md-10" flat>
<v-card-text>
<div class="my-4">
<v-row>
<v-col cols="12" class="text-center">
<h4 class="text-h4 bold">خطأ {{ error.statusCode }}</h4>
<p class="mt-4 text-body-1">
<span> {{ message }}</span>
</p>
</v-col>
</v-row>
</div>
</v-card-text>
</v-card>
<v-row class="mt-4">
<v-col cols="12" class="d-flex justify-center">
<v-btn variant="plain" class="" @click="redirectToHome"> الذهاب للصفحة الرئيسية</v-btn>
</v-col>
</v-row>
</v-col>
</v-row>
</div>
</template>
<script setup lang="ts">
import { type NuxtError, reloadNuxtApp } from '#app'
const { error } = defineProps<{
error: NuxtError
}>()
const errorMessages: Record<number, string> = {
400: 'الطلب غير صالح',
401: 'يجب تسجيل الدخول للوصول إلى هذه الصفحة',
403: 'ليس لديك صلاحية للوصول إلى هذه الصفحة',
404: 'الصفحة غير موجودة',
500: 'حدث خطأ في الخادم، يرجى المحاولة لاحقًا',
502: 'الخادم لا يستجيب حاليًا',
503: 'الخدمة غير متوفرة مؤقتًا',
}
const message = errorMessages[error.statusCode] || 'حدث خطأ غير متوقع، يرجى المحاولة لاحقًا'
const redirectToHome = async () => {
await useRouter().push('/')
reloadNuxtApp()
}
</script>
الكود السابق يمثل تصميمًا مخصصًا لصفحة الخطأ error.vue في تطبيق Nuxt مع استخدام Vuetify لتنسيق الواجهة.
عند حدوث خطأ في التطبيق (مثل صفحة غير موجودة أو خطأ في الخادم)، يتم عرض هذه الصفحة للمستخدم بدلاً من الصفحة الافتراضية.
في الجزء العلوي من الصفحة، يتم عرض رقم الخطأ (مثل 404 أو 500) بشكل واضح، وأسفله رسالة مناسبة حسب نوع الخطأ.
تم إعداد مجموعة من الرسائل المخصصة وفقًا لأكثر رموز الأخطاء شيوعًا، مثل "الصفحة غير موجودة" أو "الخدمة غير متوفرة"، ويتم اختيار الرسالة المناسبة تلقائيًا بناءً على رمز الخطأ.
أسفل الرسالة، يوجد زر يتيح للمستخدم العودة إلى الصفحة الرئيسية، وعند الضغط عليه، يتم نقله إلى الصفحة الرئيسية ويتم تحديث التطبيق (reload) لضمان استعادة الحالة الطبيعية.
الهدف من هذا الكود هو تحسين تجربة المستخدم عند حدوث مشكلة، من خلال عرض رسالة مفهومة وتصميم متناسق مع شكل التطبيق، بدلًا من صفحة خطأ تقليدية أو مفاجئة.
للمزيد حول هذا الجزء، يمكنك الرجوع للتوثيق الرسمي بالضغط هنا
نصائح إضافية
فيما يلي مجموعة من النصائح المتقدمة التي تُمكنك من التعامل مع الأخطاء بأسلوب احترافي، مع تقديم تجربة استخدام أكثر استقرارًا وموثوقية.
1- لا تُظهر التفاصيل التقنية للمستخدم
المستخدم لا يهتم برسائل الخطأ المعقدة، بل قد تسبب له القلق أو التشتت.
لذلك، من الأفضل إخفاء التفاصيل البرمجية والرسائل التي تتضمن مسارات الملفات أو أخطاء الخادم، وعرض رسالة مفهومة ومختصرة بدلاً منها، فهذا يرفع مستوى الثقة بالتطبيق ويمنح تجربة استخدام أكثر راحة.
2- اجعل الرسالة بسيطة ومفهومة
عند حدوث خطأ، لا تترك المستخدم في حيرة.
قدّم رسالة توضح ما حدث بشكل بسيط، مثل: "حدث خلل مؤقت، يرجى المحاولة لاحقًا."
أما التفاصيل الدقيقة، فاحتفظ بها في سجلات المطورين أو أدوات التتبع، لضمان حل المشكلة دون إزعاج المستخدم.
3- سجّل الأخطاء بذكاء
لا تكتف بإخفاء الخطأ، بل احرص على تسجيله لتتمكن من تتبعه لاحقًا، هذا الأمر يساعدك على تحسين التطبيق باستمرار وتفادي تكرار المشاكل.
4- فكر في واجهة بديلة عند الخطأ
في بعض الحالات، من الأفضل إظهار "واجهة بديلة" (Fallback UI) بدلاً من تعطيل الصفحة بالكامل.
مثلًا، إذا تعذّر تحميل المحتوى من الخادم، يمكنك عرض رسالة توضح أن الاتصال فُقد، مع زر لإعادة المحاولة.
هذا يمنح المستخدم شعورًا بالتحكم ويُبقيه داخل التجربة.
5- استخدم try/catch
عند التعامل مع خدمات خارجية أو عمليات غير مضمونة (مثل استدعاء API أو قراءة بيانات ديناميكية)، استخدم try/catch لضبط الأخطاء ومنع توقف التطبيق بشكل مفاجئ.
هذا يتيح لك عرض رسائل مناسبة، وتحسين استقرار التطبيق خاصة في البيئات الحقيقية.
6- اختبر سيناريوهات الخطأ قبل الإطلاق
لا تنتظر أن يكتشف المستخدمون الأخطاء أولًا.
جرّب بنفسك ماذا سيحدث عند فقد الاتصال، أو إدخال بيانات غير صحيحة، أو الوصول إلى صفحة غير موجودة.
هذه الاختبارات تساعدك على تحسين الردود وتقديم تجربة أكثر احترافية حتى في ظروف الفشل.
خاتمة
إن التعامل مع الأخطاء ليس مجرد كود إضافي، بل هو استثمار مباشر في راحة المستخدم وثقة الفريق بالتطبيق.
باستخدام إمكانيات Nuxt المتقدمة، يمكنك تصميم تجربة متماسكة حتى في أسوأ الظروف.
وتذكر دائمًا أن التطبيق الجيد لا يعني خلوه من الأخطاء، بل حسن تعامله معها.
فاستثمر وقتك في بناء تجربة متوازنة بين الأداء والوضوح.
وفقنى الله وإياك إلى ما يحبه ويرضاه ،،