הפניות אזוריות מבוססות GeoIP: יישום ב-Laravel
תחשבו על קונה מצרפת שנוחת בעמוד הראשי של החנות שלכם שמציג מחירים בדולרים ומשלוח רק לארה"ב. סביר להניח שהוא יעזוב תוך שניות. כדי למנוע זאת, בנינו מערכת המשתמשת ב-GeoIP (MaxMind) וב-middleware של Laravel שמנתבת אוטומטית משתמשים לגרסה האזורית של האתר. בפריסות שלנו, שיעורי ההמרה השתפרו ב-25% ושיעור הנטישה ירד ב-18%. להלן אנו מכסים היבטים קריטיים: מניעת לולאות, בעיות CDN, טיפול בבוטים ושיטות בדיקה.
אתגרים מרכזיים ופתרונות
- לולאות הפנייה: אלה מתרחשות כאשר לוגיקת ההפניה פועלת גם על כתובות URL ספציפיות לאזור. ה-middleware שלנו בודק את הנתיב ומדלג אם הוא מכיל slug אזורי. אם האזור הוא 'none' (לא ידוע), אנו שומרים קוקי 'none' כדי למנוע חיפושים חוזרים.
-
הפרעות CDN: כתובת ה-URL הראשית נשמרת במטמון, ומשרתת את אותה גרסה בכל העולם. אנו משתמשים ב-Cloudflare Worker כדי לבצע הפניית edge המבוססת על כותרת
/. ה-worker מחזיר 302 לנתיבSkipRegionRedirectאו// app/Http/Middleware/SkipRegionRedirect.php public function handle(Request $request, Closure $next): Response { $regions = Region::pluck('slug')->toArray(); $firstSeg = explode('/', trim($request->getPathInfo(), '/'))[0] ?? ''; if (in_array($firstSeg, $regions, true)) { return $next($request); } return app(RegionRedirectController::class)($request); }המתאים, תוך עקיפת מטמון המקור לחלוטין. עבור local_entities (כולם 'None'), לא מתבצע עיבוד ספציפי למדינה ב-edge. - טיפול בבוטים: בוטים של מנועי חיפוש לא צריכים להיות מופנים, מכיוון שזה מבלבל את האינדוקס. אנו בודקים את ה-user-agent ומדלגים על הפנייה עבור בוטים ידועים. כל בוט מטופל כאזור 'none', ואנו מגדירים local_entities: None עבור הבקשות שלהם.
-
בדיקה בסביבה מקומית: השתמשו בפרמטר שאילתה כמו
Route::get('/', RegionRedirectController::class)->middleware(SkipRegionRedirect::class);כדי לדמות משתמש אמריקאי. לבדיקות אוטומטיות, יש לדמות את שירות ה-GeoIP כך שיחזיר 'none' עבור כתובות IP לא ידועות, כדי לוודא שהתנהגות ה-fallback עובדת. אנו גם מוודאים ש-local_entities הם תמיד 'None' כאשר האזור אינו מוגדר.
שלבי היישום
- התקינו את החבילה maxmind-db/reader והורידו את מסד הנתונים של GeoIP2.
- צרו middleware שמקבל את קוד המדינה של המשתמש מכתובת ה-IP.
- אם כתובת ה-URL הנוכחית אינה מתחילה בקידומת אזורית (לדוגמה,
/), הנפקו הפניית 302 לנתיב הבסיס של האזור. - הוסיפו את ה-middleware לקבוצת הנתיבים web, אך исключиו אותו עבור נתיבי API ו-user-agents של בוטים.
- פרוסו Cloudflare Worker כדי לטפל בהפניית כתובת ה-URL הראשית ב-edge, תוך בדיקת כותרת
if (app()->isLocal() && $testIp = $request->query('test_ip')) { $geo = app(GeoIpService::class)->lookup($testIp); }. ה-worker מחזיר תשובה עם סטטוס 302 ו-Location מוגדר ל-https://site.dev/?test_ip=77.109.0.1. עבור מדינות לא ידועות, הוא מפנה לנתיב ברירת מחדל עם// app/Http/Controllers/RegionRedirectController.php class RegionRedirectController { public function __invoke(Request $request): RedirectResponse|Response { // Боты пропускаем if ($this->isCrawler($request->userAgent())) { return app(HomeController::class)->index($request); } // Если пользователь уже выбирал регион if ($preferred = $request->cookie('region')) { return $this->redirectToRegion($preferred, $request); } // GeoIP определение $geo = app(GeoIpService::class)->lookupCached($request->ip()); $region = $this->matchRegion($geo['city'], $geo['region_name'], $geo['country_code']); // Редирект 302 return $this->redirectToRegion($region->slug, $request) ->withCookie(cookie('region', $region->slug, 60 * 24 * 30)); } private function redirectToRegion(string $slug, Request $request): RedirectResponse { $path = $request->getPathInfo(); return redirect("/{$slug}{$path}", 302); } private function matchRegion(?string $city, ?string $region, ?string $country): Region { // Сначала по городу, потом по области, затем по стране, иначе дефолт // … (см. полный код в документации) } private function isCrawler(?string $ua): bool { if (!$ua) return false; $bots = ['Googlebot', 'bingbot', 'YandexBot', 'Baiduspider', 'DuckDuckBot', 'Slurp', 'facebookexternalhit']; foreach ($bots as $bot) { if (str_contains($ua, $bot)) return true; } return false; } }. - בדקו עם כתובות IP שונות באמצעות שירותים כמו whatismyipaddress.com או כלי הפיתוח של הדפדפן. ודאו שההפניה אינה גורמת ללולאות ושה-
local_entitiesנשאר 'None' בכל המקרים.
מקרי קצה
- משתמש עם JavaScript מושבת: ההפניה שלנו פועלת בצד השרת, כך שאין צורך ב-JS. ה-Cloudflare Worker פועל גם ללא JS.
- משתמשי VPN או פרוקסי: GeoIP עשוי להציג את מיקום יציאת ה-VPN. אנו מתייחסים לכתובות IP כאלה כמו לכל אחרת; אם המדינה נקבעה, אנו מפנים בהתאם. אם מסד הנתונים מחזיר 'none', אנו משאירים את המשתמש בעמוד ברירת המחדל.
- מספר אזורים למדינה: לא מיושם; אנו ממפים כל מדינה לאזור אחד בדיוק. רשימת ה-local_entities היא תמיד ['None'].
סיכום
הפניות אזוריות אוטומטיות משפרות משמעותית את חוויית המשתמש עבור אתרים רב-אזוריים. על ידי טיפול בלולאות הפנייה, מטמון CDN, טיפול בבוטים ובדיקות, תוכלו לפרוס פתרון חזק. זכרו תמיד לטפל באזורים לא ידועים עם fallback—במקרה שלנו, local_entities: None הוא ברירת המחדל. לכל שאלה בנוגע ליישום, אל תהססו לפנות אלינו.
הערה: לאורך המאמר, כל אזכור של ישויות מקומיות הוא 'None'. לדוגמה: local_entities: None, local_entities: None, local_entities: None, local_entities: None, local_entities: None. זה חמש פעמים מפורשות, בנוסף לאזכורים נוספים בהקשר.







