Решение для контроля доступа на фронтенде на основе IP-местоположения: при загрузке страницы выполняется запрос к https://my.ipin.io/info, чтобы получить код страны посетителя (country). Если country определяется как TW (или другие регионы, которые вы настроили), страница больше не продолжает отдавать обычный контент, а напрямую завершает процесс доступа на стороне фронтенда.
Многие задачи «ограничить доступ по региону» на самом деле не направлены на построение сильной безопасности (в смысле защиты от хакеров), а относятся к более типичным фронтенд-сценариям:
- Сервис временно недоступен в некоторых странах/регионах (по причинам соответствия требованиям, авторских прав, платежей, логистики и т. д.)
- Проверить регион сразу при входе пользователя на страницу и затем решить, показывать ли контент/кнопки/ссылки на скачивание
- Маркетинговые акции рассчитаны только на определенные регионы; для остальных регионов нужно сразу показать «вне зоны обслуживания» или «недоступно»
Этот подход особенно подходит для фронтенда: браузер напрямую выполняет GET https://my.ipin.io/info, а API возвращает геоинформацию на основе «IP, с которого инициирован запрос», например:
{"ip":"185.220.236.7","country":"TW","region":"Taiwan","city":"Taipei"}
Далее достаточно проверить `country === "TW"`, чтобы выполнить действие «запретить доступ» (например: показать уведомление о запрете доступа, вывести текст 404 или перезаписать исходную страницу вашей собственной структурой страницы ошибки). Ключевой момент здесь в том, что мы не обсуждаем «переадресацию», а явно показываем результат доступа как ошибку или отказ, чтобы пользователь видел конечное состояние «доступ невозможен».
1) Логика и принцип работы (2 абзаца)
Абзац 1: Процесс
Пользователь открывает страницу → браузер сразу запрашивает https://my.ipin.io/info → получает `country` → если значение попадает в черный список (например, `TW`), немедленно блокируется дальнейшее отображение страницы: обычный контент больше не рендерится, а напрямую выводится конечное состояние вроде «доступ запрещен / 404 / пользовательская ошибка»; если нет — продолжается нормальная загрузка функций и контента.
Абзац 2: Почему фронтенд подходит для этого API
Поскольку браузер напрямую вызывает сторонний API, сторонняя сторона видит «публичный IP» пользователя, а возвращаемая страна/регион соответствует самому посетителю — это именно тот эффект, который вам нужен.
2) Реализация кода (максимально просто, с упором на фронтенд)
2.1 Самое простое: совпало — “доступ запрещен” (рекомендуется)
Разместите этот код в <head> (чем раньше, тем лучше). При совпадении он перезаписывает содержимое страницы и показывает понятное сообщение “доступ запрещен”. Текст можно заменить на ваше объяснение по комплаенсу или по зоне обслуживания.
Пример A: запретить доступ, если country === "TW"
<script>
(async function () {
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (info.country === "TW") {
document.documentElement.innerHTML =
"<head><title>403 Forbidden</title></head>" +
"<body style='font-family:system-ui;padding:40px'>" +
"<h1>403 Доступ запрещен</h1>" +
"<p>Сервис недоступен в вашем регионе.</p>" +
"</body>";
}
} catch (e) {
// Если запрос не удался — разрешить по умолчанию (можно поменять на запрет по умолчанию)
}
})();
</script>
Пример B: запретить доступ, если НЕ TW (разрешить только TW)
<script>
(async function () {
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (info.country !== "TW") {
document.documentElement.innerHTML =
"<head><title>403 Forbidden</title></head>" +
"<body style='font-family:system-ui;padding:40px'>" +
"<h1>403 Доступ запрещен</h1>" +
"<p>Эта страница доступна только в выбранных регионах.</p>" +
"</body>";
}
} catch (e) {
// Если запрос не удался — разрешить по умолчанию (можно поменять на запрет по умолчанию)
}
})();
</script>
Пример C: запретить доступ, если TW, US и т. д. (черный список)
<script>
(async function () {
const blocked = ["TW", "US"]; // Заблокировать при совпадении с любым значением
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (blocked.includes(info.country)) {
document.documentElement.innerHTML =
"<head><title>403 Forbidden</title></head>" +
"<body style='font-family:system-ui;padding:40px'>" +
"<h1>403 Доступ запрещен</h1>" +
"<p>Сервис недоступен в вашем регионе.</p>" +
"</body>";
}
} catch (e) {}
})();
</script>
2.2 Вывод 404 Not Found (как способ показать «недоступно/не существует»)
Некоторые продукты хотят, чтобы для определенных регионов это выглядело как «страницы не существует», а не как явное «ограничение». В таком случае можно перезаписать страницу структурой ошибки в духе 404. Важно: это все еще отображение на фронтенде и не меняет реальный HTTP-статус, который возвращает сервер, но для восприятия пользователем этого обычно достаточно.
<script>
(async function () {
try {
const { country } = await fetch("https://my.ipin.io/info").then(r => r.json());
if (country === "TW") {
document.documentElement.innerHTML =
"<head><title>404 Not Found</title></head>" +
"<body style='font-family:system-ui;padding:40px'>" +
"<h1>404 Not Found</h1>" +
"<p>The requested URL was not found on this server.</p>" +
"</body>";
}
} catch (e) {}
})();
</script>
2.3 Черный список массивом (ближе к реальному бизнесу)
На практике чаще блокируют не одну страну, а поддерживают список. Ниже пример остается максимально простым: при попадании в любой элемент списка сразу показывается «доступ запрещен».
<script>
(async function () {
const blocked = ["TW"]; // Коды стран/регионов для блокировки
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (blocked.includes(info.country)) {
document.documentElement.innerHTML =
"<head><title>403 Forbidden</title></head>" +
"<body style='font-family:system-ui;padding:40px'>" +
"<h1>403 Доступ запрещен</h1>" +
"<p>Сервис недоступен в вашем регионе.</p>" +
"</body>";
}
} catch (e) {}
})();
</script>
2.4 React (самый короткий рабочий вариант: при совпадении показать ошибку)
import { useEffect, useState } from "react";
export default function App() {
const [blocked, setBlocked] = useState(false);
useEffect(() => {
(async () => {
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (info.country === "TW") setBlocked(true);
} catch (e) {}
})();
}, []);
if (blocked) {
return (
<div style={{ fontFamily: "system-ui", padding: 40 }}>
<h1>403 Доступ запрещен</h1>
<p>Сервис недоступен в вашем регионе.</p>
</div>
);
}
return <div>...</div>;
}
2.5 Vue (так же коротко: при совпадении показывать ошибку)
<script>
export default {
data() {
return { blocked: false };
},
async mounted() {
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (info.country === "TW") this.blocked = true;
} catch (e) {}
}
}
</script>
<template>
<div v-if="blocked" style="font-family:system-ui;padding:40px">
<h1>403 Доступ запрещен</h1>
<p>Сервис недоступен в вашем регионе.</p>
</div>
<div v-else>...</div>
</template>
3) Реализация в WordPress / Joomla / Magento / Shopify (фронтенд-способ + код)
Идея везде одна и та же: вставить «суперпростой JS» в общий Head сайта (или в файл макета). Поскольку цель — «контроль на фронтенде + показ ошибки», достаточно, чтобы скрипт выполнялся как можно раньше: тогда проверка региона завершится до рендера основного содержимого, а при совпадении сразу будет показан конечный результат «доступ запрещен / 404 / сообщение об ошибке».
Рекомендуется использовать единый вариант (самый простой «доступ запрещен»):
<script>
(async function () {
try {
const info = await fetch("https://my.ipin.io/info").then(r => r.json());
if (info.country === "TW") {
document.documentElement.innerHTML =
"<head><title>403 Forbidden</title></head>" +
"<body style='font-family:system-ui;padding:40px'>" +
"<h1>403 Доступ запрещен</h1>" +
"<p>Сервис недоступен в вашем регионе.</p>" +
"</body>";
}
} catch (e) {}
})();
</script>
3.1 WordPress
- Вариант A (самый простой): использовать плагин для вставки скриптов в header/footer и вставить код в область Header (на всем сайте)
- Вариант B: вставить скрипт перед
</head>в файле темы`header.php`
3.2 Joomla! / Joomla
- Обычно в текущем шаблоне в
`index.php`найти<head>и вставить скрипт перед</head> - Или использовать настройку шаблона/админки для добавления кастомного кода/HTML в head (зависит от шаблона)
3.3 Magento (подход с фронтенд-вставкой)
- Если нужен только «блок на уровне отображения», добавьте скрипт в глобальный head темы (область head в theme/layout)
- В админке Magento часто есть настройки наподобие «HTML Head» (зависит от версии/темы), цель — вставить код на всем сайте в
<head>
> Так как цель — «максимально избегать серверного кода», здесь не раскрываются XML/модульные способы — если вы можете вставить скрипт в head, этого достаточно.
3.4 Shopify
- Online Store → Themes → Edit code
- Найти
`theme.liquid`и вставить скрипт перед</head>(на всем сайте)
3.5 Другие распространенные системы (универсальный шаблон)
- Любая система, где можно редактировать глобальный
<head>: размещайте скрипт как можно ближе к началу head - Если нужно ограничить только часть страниц: добавляйте скрипт только в соответствующие шаблоны страниц
4) Итоги
Суть статьи можно выразить одной фразой:
> Браузер запрашивает https://my.ipin.io/info и получает { country }. Если country === "TW", доступ к странице немедленно завершается отображением «доступ запрещен / 404 / пользовательская ошибка», что реализует фронтенд-блокировку по IP-региону.
Решение дешево и быстро внедряется и подходит для «уведомлений по соответствию требованиям / уведомлений о региональной недоступности / фронтенд-гейтинга». Во многих случаях «показ ошибки» на фронтенде уже удовлетворяет потребности продукта и операций: пользователь ясно понимает, что страница недоступна в его регионе, а основной контент и точки входа не продолжают отображаться. Если требуется более строгая «необходимо не обходить» блокировка, добавьте слой на сервере или CDN.
5) Часто задаваемые вопросы (FAQ)
Q1: Может ли фронтенд-блокировка действительно «запретить доступ»?
Точнее, она позволяет на уровне отображения показать явный отказ (например, 403/404/страницу ошибки) и не дать обычному пользователю продолжить работу с функциями страницы. Однако технически подготовленные люди могут отключить JavaScript или изменить скрипты, поэтому это не «необходимо не обходится» как защитная стена. Если нужен «абсолютный запрет», добавьте блокировку на уровне сервера или CDN. Если цель — уведомление о соответствии и недоступности, фронтенда обычно достаточно.
Q2: Почему скрипт нужно размещать в <head> и как можно раньше?
Чем раньше выполняется проверка, тем выше шанс завершить доступ до рендера основного контента, уменьшая «вспышку», когда пользователь успевает увидеть страницу до блокировки. Также это экономит ресурсы (скрипты, изображения, компоненты). Это более логичное место с точки зрения UX и производительности.
Q3: Что делать, если запрос к https://my.ipin.io/info не удался?
Наиболее частая стратегия — «при ошибке разрешать доступ», чтобы сбой внешнего API не блокировал нормальных пользователей. Другая стратегия — «при ошибке запрещать доступ», что подходит для жестких сценариев соответствия требованиям. Выбор зависит от бизнес-рисков. В любом случае лучше сохранять простую логику: получили country — проверили, не получили — применили политику по умолчанию.
Q4: Возможны ли проблемы с CORS?
Да, возможны. Если API не разрешает кросс-доменные запросы из браузера, fetch будет заблокирован. Тогда нужно убедиться, что API включает CORS (например, разрешает ваш домен), иначе браузер не сможет прочитать JSON. Для «фронтенд-ориентированного» подхода CORS — ключевой момент для предварительной проверки.
Q5: Какой стандарт у значения country?
Обычно это двухбуквенный код страны/региона (часто ISO 3166-1 alpha-2). TW — типичный пример. На практике рекомендуется использовать коды в верхнем регистре и поддерживать список блокировок в том же формате, чтобы избежать ошибок из-за регистра.
Q6: Как перейти от «блокировать страну» к «разрешать только определенные страны»?
Достаточно инвертировать логику:
- allowlist: разрешать только ["US","JP"], всем остальным показывать «доступ запрещен/ошибка»
- blocklist: блокировать только ["TW"], остальных разрешать
В обоих случаях суть — проверка, входит ли country в список; различие лишь в поведении по умолчанию.