Magento 2 - Перенаправление Гео IP и лакирование
Мы запускаем магазин Magento 2.1.8 с модулем перенаправления IP-адресов Amasty Geo.
К сожалению, он неправильно работает с лаком. Амасти написал, что сейчас они не знают рабочего решения. Я поискал другие модули - все они сейчас не работают с лаком.
Есть ли у кого-нибудь идеи, как этого добиться?
Наше текущее состояние таково, что параметры сеанса для модуля перенаправления не записаны, и пользователь перенаправляется каждый раз. Так что переключение хранить невозможно.
Это серьезная проблема для нас. Отключение лака не является решением, так как необходимо повысить производительность.
5 answers
Ладно, похоже, у меня все получилось после борьбы. В нашем случае мы всегда перенаправляем первого посетителя в нужный магазин. Перенаправление непосредственно с Лака. Никакого обхода.
Это очень грязно, но если у кого-то есть лучшее решение, не стесняйтесь размещать его здесь.
Установить модуль ГеоИП Лака
https://rageagainstshell.com/2016/05/geoip-location-in-varnish/
Убедитесь, что вы клонировали правильную ветвь (относительно вашей версии лака)
иначе это не сработает. В моем случае это было: git clone https://github.com/varnish/libvmod-geoip --branch=4.1
Добавьте это в начало файла с лаком. (Скорее всего, в /etc/лак/default.vcl) добавитьimport geoip;
Внутри раздела sub vcl_recv добавьте что-то вроде этого:
if (req.http.Cookie !~ "PHPSESSID=") {
set req.http.X-Country-Code = geoip.country_code(req.http.X-Forwarded-For);
if(req.url !~ "/(pub/)?(media|static)/") {
if (req.url !~ "/de/" && req.http.X-Country-Code == "DE") {
set req.http.subshop = "/de/";
return (synth(750, "Redirect"));
} elseif (req.url !~ "/us/" && req.http.X-Country-Code ~ "(US|MX|CA)") {
set req.http.subshop ="/us/";
return (synth(750, "Redirect"));
}
}
}
Если сеанс уже есть -> Неважно
В противном случае проверьте, не является ли запрос статическим файлом
Затем проверьте, находится ли пользователь уже в правильном магазине. В противном случае установите переменную для последующего использования (см. Ниже)
Возвращает ошибку синтезатора.
В нижней части ваш файл по умолчанию.vcl добавьте это для перенаправления:
sub vcl_synth {
if (resp.status == 750) {
if(req.url != resp.http.Location) {
set resp.status = 301;
set resp.http.Location = req.http.subshop + regsuball(req.url, "^(/de/|/us/|)","")
}
return (deliver);
}
}
Сначала предотвратите циклы перенаправления. Установить статус ответа на перенаправление Удалите коды store_view_codes из URL-адреса и замените его правильным.
Я реализовал то, что, на мой взгляд, является лучшим сверхпроектным решением, по крайней мере, для нашего варианта использования. Мы не используем Гео-IP-перенаправление Amasty. Вместо этого мы решили разработать собственное индивидуальное решение, которое, вероятно, в конечном итоге оказалось довольно похожим. Плагин для метода отправки интерфейсного контроллера, я полагаю?
Наш вариант использования
Мы запускаем несколько веб-сайтов, каждый с одной группой/магазином, и все они находятся в одном домене. Наши веб-сайты относятся к нашим регионам обслуживания, поэтому имеют очень динамические страны, заданные в конфигурации Magento.
Наши требования
- Посетители в первый раз никогда не должны обходить кэш лаков, по крайней мере, не для рендеринга страницы.
- Лак должен обслуживать правильную версию из кэша на основе гео-IP.
- Конфигурация Magento все равно должна определять, какой веб-сайт обслуживается, поэтому виртуальные модули GeoIP и жестко закодированные регулярные выражения отсутствуют.
Наше Решение
Давайте извлекем заголовок X-Magento-Vary из серверная часть, использующая легкую конечную точку, затем используйте ее для обслуживания правильной страницы из кэша. Это позволит первым делом доставить посетителей в нужный регион, что минимально повлияет на производительность. После долгих исследований я решил решить эту проблему с помощью cUrl VMOD. HTTP VMOD не был для нас вариантом, потому что мы используем Varnish v4.
Вот основной рэп:
Добавьте облегченную конечную точку в пользовательский модуль Magento для возврата заголовка X-Magento-Vary. Я добавил простое контроллер, который возвращает RESULT_RAW без содержимого, только заголовки. Эта конечная точка должна выполнить логику в вашем модуле перенаправления, чтобы установить правильное хранилище, самое главное, обновив значения контекста HTTP, чтобы убедиться, что в файлах cookie возвращается правильная строка vary.
Установите VMOD curl: https://github.com/varnish/libvmod-curl
Объедините следующее в свой файл .vcl, заменив путь завитка своим легким конечная точка
`
... Import the cUrl VMOD
import curl;
...
sub vcl_recv {
... # After all your return(pass) logic, get vary header from the backend if not yet checked
# For first time visitors, determine X-Magento-Vary hash via backend API call that uses geo-ip
if (req.http.cookie !~ "X-Varnish-GeoIP=") {
# Copy required headers. Host and Proto prevent redirect,
# Forwarded-For sets correct IP for geo-IP lookup behind proxies
curl.header_add("X-Forwarded-For: " + req.http.X-Forwarded-For);
curl.header_add("X-Forwarded-Proto: https");
curl.header_add("Host: " + req.http.host);
curl.get("http://127.0.0.1:8080/geoip/redirect/varnishService");
if (curl.header("Set-Cookie") ~ "X-Magento-Vary="){
if (req.http.cookie){
set req.http.cookie = req.http.cookie +
"; " + regsub(curl.header("Set-Cookie"), "^.*?(X-Magento-Vary=[^;]+);*.*$", "\1");
} else {
set req.http.cookie = regsub(curl.header("Set-Cookie"), "^.*?(X-Magento-Vary=[^;]+);*.*$", "\1");
}
# Set store cookies so it's sent back to the backend for a cache MISS. This prevents subsequent geo-IP lookup
if (curl.header("Set-Cookie") ~ "store="){
set req.http.cookie = req.http.cookie +
"; " + regsub(curl.header("Set-Cookie"), "^.*?(store=[^;]+);*.*$", "\1");
}
}
}
...
}
...
sub vcl_deliver {
... An attempt has been made to get the Vary header, this cookie stops subsequent checks.
if (curl.status() > 0){
# It would be better to not rely on user-sent cookie but AFAIK there's not a way to store a persistent variable in varnish.
if (resp.http.Set-Cookie){
set resp.http.Set-Cookie = resp.http.Set-Cookie + "; X-Varnish-GeoIP=true; path=/; domain=" + req.http.Host + ";";
} else {
set resp.http.Set-Cookie = "X-Varnish-GeoIP=true; path=/; domain=" + req.http.Host + ";";
}
}
...
}
`
Файл cookie X-Varnish-GeoIP гарантирует, что серверная часть в большинстве случаев вызывается только один раз. Это было лучшее решение, чем полагаться на файлы cookie магазина или сеанса.
Устранение неполадок
Я столкнулся с различными проблемами при реализации своего решения. Я тестировал как встроенные, так и настроенные на лак экземпляры Magento, так как хотел иметь возможность отключить лак, если у нас возникнут какие-либо проблемы. Вот некоторые с которыми я столкнулся.
Изначально мы использовали наблюдатель событий controller_action_predispatch для нашего перенаправления GeoIP. Это приводило к отсутствию кэша для встроенного кэша при первом посещении магазинов, отличных от стандартного. Причина, по которой это произошло, заключается в том, что кэш страниц использует плагин around, который всегда выполняется перед отправкой события. Мы перенесли нашу логику перенаправления в плагин BeforeMethod с сортировщиком-1, чтобы гарантировать, что он всегда выполняется перед кэшем страницы плагины.
При переключении на новое представление магазина убедитесь, что вы также обновили объект \Magento\Framwork\App\Http\Context новыми значениями. Невыполнение этого требования может привести к кэшированию возвращаемой страницы с использованием неправильной строки X-Magento-Vary.
Ниже приведен код, который мы используем для установки нового представления магазина в нашем плагине bEforeDispatch (точно имитирует \Magento\Store\Модель\Storeswitcher). Обратите внимание, что в хранилище по умолчанию нет файла cookie хранилища или набора заголовков, который является По умолчанию в Magento.
`
$this->storeManager->setCurrentStore($store->getCode());
$defaultStoreView = $this->storeManager->getDefaultStoreView();
if ($defaultStoreView !== null) {
if ($defaultStoreView->getId() === $store->getId()) {
$this->storeCookieManager->deleteStoreCookie($store);
$this->httpContext->unsValue(Store::ENTITY);
$this->httpContext->unsValue(Context::CONTEXT_CURRENCY);
} else {
$this->httpContext->setValue(Store::ENTITY, $store->getCode(), $defaultStoreView->getCode());
$this->httpContext->setValue(Context::CONTEXT_CURRENCY, $store->getDefaultCurrencyCode(), $defaultStoreView->getDefaultCurrencyCode());
$this->storeCookieManager->setStoreCookie($store);
}
}
`
Другое Решение?
Эта проблема более или менее исчезла бы, если бы мы использовали отдельные домены для каждого представления магазина. Созданный Magento vcl добавляет домен в хэш, поэтому при использовании отдельных доменов внутренний поиск в этом решении по существу заменяется любым посещаемым доменом. Однако в этом случае пользователи, которые вошли через неправильный домен, не будут перенаправлены на нужный веб-сайт. Это еще одно преимущество нашего решения, хотя и накладные расходы на вызов внутреннего API.
У Amasty есть частичное решение здесь Путем обхода лака, если это пользователи, впервые посещающие сайт.
После того, как я сошел с ума, чтобы найти решение для этого, наконец, я получил рабочее решение для Magento 2.3.2 + Лак + GeoIP. Для этого вы можете использовать Cache Context
и Page Variations
, которые очень просты в реализации.
Сначала создайте плагин в свой модуль для Magento\Framework\App\Http\Context
.
Файл: app/code/Vendor/YourModule/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Framework\App\Http\Context">
<plugin name="atwix_country_cache_context_plugin"
type="Vendor\YourModule\Plugin\CustomerCountryCacheContextPlugin" />
</type>
</config>
Затем реализация плагина
Файл: Vendor/YourModule/Plugin/CustomerCountryCacheContextPlugin.php
/**
* Plugin on \Magento\Framework\App\Http\Context
*/
class CustomerCountryCacheContextPlugin
{
public function __construct(
\Magento\Customer\Model\Session $customerSession
) {
$this->customerSession = $customerSession;
}
/**
* \Magento\Framework\App\Http\Context::getVaryString is used by Magento to retrieve unique identifier for selected context,
* so this is a best place to declare custom context variables
*/
function beforeGetVaryString(\Magento\Framework\App\Http\Context $subject)
{
$country = $this->yourWayToGetTheCountry();
$defaultCountryContext = 'Brazil';
$subject->setValue('CONTEXT_AGE', $country, $defaultCountryContext);
}
}
И последний шаг - добавить файл cookie X-Magento-Vary
для передачи контекста на HTTP-слое в вашем лаке.
sub vcl_hash {
if (req.http.cookie ~ "X-Magento-Vary=") {
hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
}
... more ...
}
Для получения дополнительной информации посетите:
Https://www.atwix.com/magento-2/cache-context-and-page-variations-in-magento-2/
Я нашел простой способ решить свою проблему, просто обновив способ хэширования моего запроса: в моем случае я использую cloudflare, и он отправляет дополнительный запрос на мой сервер, и я использовал этот запрос для создания уникального хэша на его основе:
В файл VCL
sub vcl_hash {
if (req.http.cookie ~ "X-Magento-Vary=") {
hash_data(regsub(req.http.cookie+req.http.cf-ipcountry, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
}
# For multi site configurations to not cache each other's content
if (req.http.host) {
hash_data(req.http.host+req.http.cf-ipcountry);
} else {
hash_data(server.ip+req.http.cf-ipcountry);
}
# To make sure http users don't see ssl warning
#if (req.http.X-Forwarded-Proto) {
# hash_data(req.http.X-Forwarded-Proto);
#}
if (req.url ~ "/graphql") {
call process_graphql_headers;
Теперь первый пользователь из новой страны будет пропущен, а другой - из кэша
Для получения более подробной информации мой первый пост здесь
Https://magento2develop.blogspot.com/2020/02/geoip-magento-2-varnish-cloudflare.html