سرور را باز میکنید، آدرس یک محصول حذفشده را میزنید و بهجای صفحه ۴۰۴ سایت، صفحه پیشفرض Apache را میبینید: «Not Found. The requested URL was not found on this server.» یا بدتر، سایت روی همه آدرسهای اشتباه کد ۲۰۰ برمیگرداند و گوگل هزاران صفحه تکراری را ایندکس میکند. مشکل معمولاً در تنظیم ErrorDocument است، نه در خود فایل خطا.
قبل از هر چیز یک چیز را روشن کنیم: صفحه خطای سفارشی فقط ظاهر ماجرا نیست. اگر کد وضعیت همراه آن اشتباه باشد، هر کاری بکنید نتیجه معکوس میگیرید. این مقاله دقیقاً درباره همان مرز است.
چرا صفحه خطای سفارشی بدون کد وضعیت درست بیفایده است
وقتی کاربر به آدرسی میرسد که وجود ندارد، سرور باید در هدر پاسخ بنویسد HTTP/1.1 404 Not Found. اگر این کد ۲۰۰ باشد، مرورگر و خزنده گوگل هر دو فکر میکنند صفحه سالم است. نتیجهاش را در Search Console میبینید: دهها هزار «صفحه ایندکسشده» که هیچکدام محتوای واقعی ندارند و بودجه خزش سایت را میخورند.
راه درست این است که فایل خطا را با دستور ErrorDocument معرفی کنید، نه با ریدایرکت. تفاوت این دو را در ادامه میبینید.
تفاوت ErrorDocument با Redirect 404
اینجا اشتباه میکنند: در .htaccess مینویسند Redirect 404 /404.html و خیالشان راحت میشود. این دستور یک ریدایرکت ۳۰۲ میسازد؛ یعنی سرور اول کد ۳۰۲ میدهد، بعد مرورگر میرود /404.html را با کد ۲۰۰ بگیرد. گوگل آدرس اشتباه را «موقتاً منتقلشده» میفهمد و آن را در صف ایندکس نگه میدارد. علامتش هم این است که در گزارش پوشش، آدرسهای ۴۰۴ شما زیر دسته «تغییر مسیر دادهشده» ظاهر میشوند، نه «یافت نشد».
درستترین شکل، این خط است:
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html
ErrorDocument 403 /errors/403.html
مسیر باید از ریشه دامنه شروع شود و با اسلش آغاز گردد. اگر بنویسید ErrorDocument 404 errors/404.html بدون اسلش اول، Apache آن را نسبی تفسیر میکند و بسته به عمق آدرس درخواستی، نتیجه فرق میکند. این خطای کوچک باعث میشود صفحه خطا فقط در ریشه سایت کار کند و در مسیرهای عمیقتر دوباره صفحه پیشفرض برگردد.
محتوایی که کاربر را برمیگرداند، نه صفحهای که او را رها میکند
صفحه ۴۰۴ خوب سه کار میکند و بس. اول، در یک جمله میگوید چه اتفاقی افتاده. دوم، سه یا چهار مسیر واقعی پیش پایش میگذارد. سوم، یک راه جستوجو یا تماس میدهد. بقیهاش تزئین است.
- عنوان صفحه باید همان چیزی باشد که کاربر انتظار دارد: «صفحه مورد نظر پیدا نشد».
- لینک به صفحه اصلی، دستهبندیهای اصلی، و اگر فروشگاه دارید، سبد خرید.
- یک فرم جستوجوی ساده که به نتایج داخلی سایت وصل باشد.
- اگر آدرس شبیه یک محصول حذفشده است، لینک به نزدیکترین محصول موجود.
چیزی که در عمل جواب میدهد، پیشنهاد هوشمند بر اساس آدرس است. اگر آدرس درخواستی با یکی از مسیرهای موجود شباهت زیادی داشته باشد، همان را پیشنهاد بدهید. یک اسکریپت کوچک PHP با similar_text() یا levenshtein() روی فهرست آدرسهای سایت، در بیشتر موارد کاربر را به مقصد درست میرساند. هزینهاش این است که باید فهرست آدرسها را جایی نگه دارید و بهروز نگه دارید؛ برای سایتهای زیر چند هزار صفحه ارزش دارد، برای سایتهای کوچک نه.
صفحه ۵۰۰ را دستکم نگیرید
صفحه ۵۰۰ با ۴۰۴ فرق بنیادی دارد: کاربر مقصر نیست، شما هستید. اینجا نباید هیچ جزئیات فنی نشان دهید. پیام Fatal error: Uncaught Error: Call to undefined function روی صفحه، هم آبروی فنی میبرد و هم مسیر سوءاستفاده باز میکند.
در php.ini یا با ini_set این دو مقدار را تنظیم کنید:
display_errors = Off
log_errors = On
error_log = /home/USERNAME/logs/php_errors.log
مسیر لاگ را با مسیر واقعی هاست خودتان عوض کنید. اگر مطمئن نیستید کدام دستور php.ini روی هاست شما اثر دارد، مرجع تنظیمات php.ini هر دستور را با مقدار پیشفرض و اثر عملیاش فهرست کرده است.
نکتهای که کمتر گفته میشود: ErrorDocument 500 فقط وقتی کار میکند که خود Apache خطا را تولید کند. اگر PHP با خطای مرگبار بمیرد و خروجی ناقص بفرستد، Apache ممکن است آن را پاسخ سالم تلقی کند و صفحه سفارشی شما نمایش داده نشود. برای پوشش این حالت، باید در سطح اسکریپت هم یک error handler ثبت کنید یا از auto_prepend_file استفاده کنید.
تنظیم در htaccess یا در پنل هاست؟
هر دو راه وجود دارد و انتخاب بینشان به شرایط شما بستگی دارد.
| روش | مزیت | محدودیت |
|---|---|---|
ErrorDocument در .htaccess | سریع، قابل انتقال با فایل، بدون نیاز به دسترسی ادمین | روی هر دامنه جداگانه باید تکرار شود؛ اگر AllowOverride محدود باشد کار نمیکند |
| تنظیم در VirtualHost | در سطح سرور، روی همه دامنهها یکجا | نیاز به دسترسی root یا پنل مدیریت سرور |
| تنظیم در پنل هاست | بدون دستزدن به فایل، مناسب کاربر غیرفنی | انعطاف کمتر، گاهی فقط مسیر ثابت میپذیرد |
اگر روی هاست لینوکس کار میکنید و به فایلها دسترسی دارید، من .htaccess را انتخاب میکنم. دلیلش ساده است: با یک فایل میتوانید تنظیمات را در گیت نگه دارید و بین محیط تست و پروداکشن جابهجا کنید. اگر دهها دامنه روی یک سرور دارید و میخواهید همهشان یک صفحه خطای مشترک داشته باشند، سرور اختصاصی با تنظیم در سطح VirtualHost کمدردسرتر است.
یک محدودیت عملی که زیاد به آن میخورم: وقتی سایت پشت CDN است، صفحه خطای سفارشی شما ممکن است هرگز به کاربر نرسد. بعضی CDNها پاسخهای ۴۰۴ و ۵۰۰ را با صفحه خودشان جایگزین میکنند. اگر بعد از تنظیم درست، هنوز صفحه غریبهای میبینید، اول هدر پاسخ را با curl -I https://example.com/not-found چک کنید و ببینید سرور شما چه کدی میفرستد.
بررسی اینکه واقعاً کار میکند
تنظیم را که نوشتید، حدس نزنید. تست کنید:
curl -sI https://example.com/this-page-does-not-exist | head -n 1
curl -s https://example.com/this-page-does-not-exist | grep -i "صفحه مورد نظر"
خط اول باید HTTP/2 404 برگرداند. اگر HTTP/2 200 دیدید، یعنی جایی ریدایرکت یا rewrite دارید که کد را عوض میکند. رایجترین مقصر، قاعدهای در .htaccess است که همه چیز را به index.php میفرستد و آن هم بدون بررسی، کد ۲۰۰ میدهد. اگر از فریمورک استفاده میکنید، این رفتار پیشفرض بعضی روترهاست و باید در خود کد اصلاح شود، نه در htaccess.
برای دیدن اینکه سرور در لایه شبکه چه میگوید و مشکل از DNS نیست، ابزار بررسی DNS و شبکه سریعترین راه است. و اگر میخواهید مطمئن شوید خطای ۵۰۰ از یک افزونه PHP میآید نه از کانفیگ، فهرست افزونههای فعال را با راهنمای بررسی افزونههای PHP مقایسه کنید.
سه اشتباهی که مرتب تکرار میشود
- لینک دادن از صفحه ۴۰۴ به صفحه ۴۰۴. اگر منوی سایت شما به آدرسهایی لینک میدهد که خودشان ۴۰۴ هستند، کاربر در حلقه میافتد. منو را روی صفحه خطا حذف کنید یا فقط لینکهای سالم را نگه دارید.
- گذاشتن
noindexروی صفحه ۵۰۰. صفحه ۵۰۰ نباید ایندکس شود، ولی این کار با کد وضعیت انجام میشود نه با متا تگ. اگر کد ۵۰۰ درست باشد، گوگل خودش ایندکس نمیکند. - فراموش کردن دامنههای فرعی.
ErrorDocumentدر.htaccessریشه، رویblog.example.comاثر ندارد. هر دامنه فرعی فایل خودش را میخواهد.
یک نکته درباره صفحه ۴۰۴ و سئو: اگر صفحهای را عمداً حذف کردهاید و میدانید بکلینک دارد، ۴۰۴ اشتباه است. آنجا باید ۳۰۱ بدهید. ۴۰۴ برای آدرسهایی است که واقعاً نباید وجود داشته باشند.
پرسشهای پرتکرار
آیا صفحه خطای سفارشی روی رتبه سئو اثر دارد؟
خودِ صفحه اثر مستقیم ندارد؛ چیزی که اثر دارد کد وضعیت است. اگر صفحه ۴۰۴ شما کد ۴۰۴ برگرداند، گوگل آن را از ایندکس حذف میکند و مشکلی نیست. اگر کد ۲۰۰ برگرداند، صفحات بیمحتوا در ایندکس جمع میشوند و بودجه خزش هدر میرود.
چرا بعد از تنظیم ErrorDocument هنوز صفحه پیشفرض Apache را میبینم؟
سه دلیل رایج دارد: مسیر فایل با اسلش شروع نشده، فایل خطا در مسیر درست آپلود نشده، یا AllowOverride در تنظیمات Apache اجازه خواندن ErrorDocument از .htaccess را نمیدهد. با یک فایل تست ساده و curl -I هر سه را میتوانید در چند دقیقه رد کنید.
صفحه ۵۰۰ را چطور بسازم وقتی خود سایت بالا نمیآید؟
فایل خطا باید HTML خالص و بدون وابستگی باشد؛ نه PHP، نه فراخوانی دیتابیس، نه فایل CSS خارجی. اگر صفحه ۵۰۰ شما به همان چیزی وابسته باشد که خراب شده، هرگز نمایش داده نمیشود. یک فایل HTML ساده با استایل درونخطی بسازید و همان را معرفی کنید.
آیا میتوانم برای هر دامنه صفحه خطای متفاوتی داشته باشم؟
بله. ErrorDocument در .htaccess هر دامنه جداگانه اعمال میشود، پس کافی است فایل خطای مخصوص همان دامنه را در ریشهاش قرار دهید. فقط یادتان باشد دامنههای فرعی که DocumentRoot جدا دارند فایل جدا میخواهند.
همین حالا یک آدرس ناموجود را در مرورگر باز کنید و هدر پاسخ را با curl -I ببینید. اگر عدد اول ۴۰۴ نبود، بقیه کارها را متوقف کنید و اول همان را درست کنید.