سایت را بازطراحی کردهاید، ساختار دستهها عوض شده و حالا Search Console دارد روزی چند صد خطای 404 نشان میدهد. اگر همین امروز شروع به ساختن نقشه ریدایرکت نکنید، هر روزی که بگذرد بخشی از اعتبار لینکهای قدیمی و ترافیک ورودی از بین میرود. خبر خوب این است که این کار یکبار برای همیشه انجام میشود؛ به شرطی که با روش درست جلو بروید.
اول فهرست آدرسهای قدیمی را از داده واقعی بسازید
بیشتر تیمها این مرحله را از روی حافظه انجام میدهند و بعد تعجب میکنند که چرا ترافیک برنگشت. آدرسهایی که واقعاً بازدید داشتهاند، در سه جا ثبت شدهاند: لاگ دسترسی وبسرور، گزارش عملکرد Search Console، و بکلینکهای خارجی. هر سه را استخراج کنید و در یک فایل CSV بریزید.
از لاگ سرور، فقط درخواستهای موفق قدیمی را جدا کنید. اگر وبسرور Nginx است:
awk '{print $7}' /var/log/nginx/access.log \
| grep -E '^/(blog|products|category)/' \
| sort | uniq -c | sort -rn | head -500
خروجی این دستور ستون اولش تعداد بازدید و ستون دومش مسیر است. ستون دوم را بردارید، دامنه را به آن بچسبانید و به فهرست اضافه کنید. برای Search Console، از بخش Pages گزارش Performance، بازه را روی ۱۶ ماه بگذارید و خروجی CSV را دانلود کنید. ستون «آدرس» همان چیزی است که لازم دارید.
یک نکته که کمتر گفته میشود: آدرسهای با پارامتر query را جدا نگه دارید. ریدایرکت کردن /product?id=42 به یک صفحه ثابت، تقریباً همیشه اشتباه است، چون آن پارامتر ممکن است بعداً معنای دیگری پیدا کند.
نگاشت یکبهیک، نه ریدایرکت همه به صفحه اصلی
وسوسهای وجود دارد که همه چیز را به / ریدایرکت کنید. این کار از نظر فنی جواب میدهد و از نظر سئو فاجعه است. گوگل ریدایرکت انبوه به صفحه اصلی را بهعنوان soft 404 تفسیر میکند و اعتبار لینکها را منتقل نمیکند. هر آدرس قدیمی باید به نزدیکترین معادل موضوعی خودش برود.
برای این کار یک جدول دو ستونی بسازید: مبدأ و مقصد. مبدأ باید مسیر کامل بدون دامنه باشد، مقصد باید آدرس نهایی و کانونیکال باشد. اگر صفحهای معادل ندارد، به نزدیکترین دسته والد ریدایرکت کنید، نه به خانه.
| وضعیت آدرس قدیمی | مقصد درست | کد وضعیت |
|---|---|---|
| معادل دقیق دارد | همان صفحه جدید | 301 |
| در دسته جدید ادغام شده | صفحه دسته جدید | 301 |
| کاملاً حذف شده | نزدیکترین دسته والد | 301 |
| موقتاً در دست تعمیر | همان مسیر | 302 |
| محتوای تکراری حذفشده | نسخه کانونیکال | 410 یا 301 |
کد 410 برای صفحاتی است که واقعاً دیگر وجود ندارند و نمیخواهید معادلی داشته باشند. تفاوتش با 404 این است که به گوگل میگوید این حذف عمدی و دائمی است، پس سریعتر از فهرست خارج میشود. اما اگر آن صفحه بکلینک ارزشمند دارد، 410 اشتباه است؛ باید 301 بزنید.
نقشه را کجا پیاده کنید: وبسرور یا اپلیکیشن
دو جای اصلی برای اعمال ریدایرکت وجود دارد و انتخاب بینشان روی سرعت و نگهداری اثر میگذارد. اگر تعداد قواعد زیر چند صد مورد است و ساختار ثابت است، لایه وبسرور انتخاب درست است. اگر قواعد از دیتابیس میآیند یا مدیر محتوا باید بدون دسترسی SSH آنها را ویرایش کند، لایه اپلیکیشن منطقیتر است.
در Nginx، قاعدهها را در بلوک server بنویسید. برای ریدایرکت گروهی یک الگو، از map استفاده کنید که سریعتر از زنجیره if است:
map $uri $redirect_target {
/old-blog/post-1 /blog/new-post-1;
/old-blog/post-2 /blog/new-post-2;
/category/php /categories/php-hosting;
default "";
}
server {
listen 443 ssl;
server_name example.com;
if ($redirect_target) {
return 301 $redirect_target;
}
}
در Apache، معادلش فایل .htaccess است:
Redirect 301 /old-blog/post-1 /blog/new-post-1
RedirectMatch 301 ^/category/php/?$ /categories/php-hosting
هزینهای که این روش دارد: هر قاعده اضافه یک مقایسه اضافه در هر درخواست است. با چند هزار قاعده، تأخیر محسوس میشود. راهحل عملی این است که قواعد پرترافیک را بالای فایل بگذارید و قواعد نادر را در یک فایل جدا با RewriteMap نگه دارید. اگر روی هاست لینوکس کار میکنید، قبل از افزودن هزاران خط به .htaccess، با پشتیبانی درباره محدودیت حجم فایل و بار پردازشی مشورت کنید.
قبل از اعمال، دستهای تست کنید
اعمال نقشه روی سایت زنده بدون تست، همان اشتباهی است که سایت را برای چند ساعت از دسترس خارج میکند. اول روی یک محیط staging یا با تغییر هدر Host تست کنید. سادهترین راه، تست با curl روی فهرست مبدأهاست:
while read -r src dst; do
code=$(curl -s -o /dev/null -w "%{http_code}" -I "https://example.com$src")
loc=$(curl -s -o /dev/null -w "%{redirect_url}" -I "https://example.com$src")
echo "$src -> $code -> $loc"
done < redirects.txt
خروجی درست چیزی شبیه این است:
/old-blog/post-1 -> 301 -> https://example.com/blog/new-post-1
اگر بهجای 301 عدد 200 دیدید، یعنی قاعده اعمال نشده. اگر 302 دیدید، یعنی جایی کد اشتباه نوشته شده. اگر زنجیرهای از 301ها دیدید، یعنی مقصد خودش هم ریدایرکت میشود و این همان چیزی است که باید حذف شود.
اینجا اشتباه میکنند
رایجترین اشتباهی که واقعاً دیدهام: ریدایرکت HTTP به HTTPS و ریدایرکت ساختار جدید همزمان و بدون ترتیب اعمال میشوند و حلقه میسازند. نشانهاش این است که مرورگر پیام ERR_TOO_MANY_REDIRECTS میدهد و curl با -L بعد از ۲۰ پرش متوقف میشود. علتش معمولاً این است که قاعده HTTPS بعد از قاعده ساختار قرار گرفته و مقصد ریدایرکت دوم دوباره به نسخه HTTP اشاره میکند. ترتیب درست این است: اول HTTP به HTTPS، بعد ساختار. برای اینکه این مرحله را بدون حلقه رد کنید، راهنمای نصب SSL روی هاست و اجبار HTTPS بدون حلقه ریدایرکت را قبل از نوشتن قواعد بخوانید.
اشتباه دوم که کمتر دیده میشود ولی دردناکتر است: ریدایرکت کردن آدرسهایی که هنوز در نقشه سایت (sitemap) هستند. نتیجهاش این است که گوگل هر روز همان آدرسها را میخزد، 301 میگیرد و بودجه خزش هدر میرود. بعد از اعمال نقشه، sitemap را هم بهروز کنید.
بعد از اعمال چه چیزی را رصد کنید
نقشه ریدایرکت یک فایل زنده است، نه یک کار تمامشده. در دو هفته اول بعد از اعمال، روزانه گزارش Pages را در Search Console چک کنید. اگر تعداد آدرسهای 404 بالا رفت، یعنی بخشی از نقشه را جا انداختهاید. اگر تعداد «Page with redirect» بالا رفت ولی ترافیک برنگشت، یعنی مقصدها معادل موضوعی درستی ندارند.
یک عدد که ارزش اندازهگیری دارد: زمان پاسخ سرور برای درخواستهای ریدایرکتشده. اگر TTFB این درخواستها از چند صد میلیثانیه بیشتر شد، احتمالاً قواعد زیادی در .htaccess انبار کردهاید یا سرور به منابع بیشتری نیاز دارد. برای سایتهای پرترافیک، انتقال به سرور اختصاصی و پیادهسازی ریدایرکت در لایه Nginx بهجای Apache، تفاوت محسوسی در همین عدد ایجاد میکند.
برای بررسی اینکه ریدایرکتها درست کار میکنند و DNS و مسیر شبکه مشکلی ندارد، از ابزار بررسی DNS و شبکه استفاده کنید. اگر میخواهید قبل از اعمال نهایی، رفتار هدرها را در محیط واقعی ببینید، ابزارهای رایگان وبمستر گزینه سریعتری از راهاندازی staging است.
پرسشهای پرتکرار
تفاوت ریدایرکت 301 و 302 در نقشه ریدایرکت چیست؟
کد 301 یعنی انتقال دائمی و اعتبار لینک را به مقصد منتقل میکند. کد 302 یعنی انتقال موقت و گوگل آدرس مبدأ را در فهرست نگه میدارد. برای تغییر ساختار همیشه 301 بزنید. 302 فقط برای حالتهای موقت مثل تعمیرات یا تست A/B کاربرد دارد.
اگر اشتباهاً 302 زدهاید و بعداً به 301 تغییرش میدهید، مشکلی نیست؛ فقط بدانید که تا آن زمان اعتبار لینک منتقل نشده است.
آیا باید همه آدرسهای قدیمی را ریدایرکت کنم؟
نه. فقط آدرسهایی که بازدید یا بکلینک داشتهاند ارزش ریدایرکت دارند. آدرسهای بیبازدید را میتوانید رها کنید تا 404 بمانند یا 410 بزنید. ریدایرکت کردن هزاران آدرس بیارزش، فقط فایل قواعد را سنگین و نگهداریاش را سخت میکند.
چطور بفهمم ریدایرکتها حلقه زدهاند؟
با curl -sIL https://example.com/old-path زنجیره هدرها را ببینید. اگر بیش از دو یا سه پرش دیدید یا مرورگر ERR_TOO_MANY_REDIRECTS داد، حلقه دارید. علت تقریباً همیشه ترتیب اشتباه قواعد HTTP/HTTPS و ساختار است.
نقشه ریدایرکت را در Nginx بنویسم یا .htaccess؟
اگر کنترل کامل سرور را دارید، Nginx انتخاب بهتری است چون قواعد در حافظه نگه داشته میشوند و روی هر درخواست فایل خوانده نمیشود. اگر روی هاست اشتراکی هستید و دسترسی به کانفیگ Nginx ندارید، .htaccess تنها گزینه است. در هر دو حالت، فهرست مبدأ و مقصد را جدا از کانفیگ نگه دارید تا مهاجرت بعدی ساده باشد.