Поддомен представляет собой часть доменной структуры, расположенную
слева от основного домена. Например, в api.example.com
поддоменом является api, а в
v1.api.example.com — уже цепочка поддоменов
v1.api.
Структурно доменные имена подчиняются строгим правилам:
Валидация поддоменов в JavaScript обычно решается не одной функцией, а комбинацией инструментов:
Библиотека Validator.js предоставляет базовые функции, которые можно использовать как основу.
isFQDN для проверки доменаОсновной инструмент — isFQDN (Fully Qualified Domain
Name).
const validator = require('validator');
validator.isFQDN('example.com');
Функция возвращает true для корректных доменов и
false для некорректных.
По умолчанию isFQDN не ограничивает наличие поддоменов,
но позволяет валидировать всю структуру домена.
validator.isFQDN('api.example.com'); // true
validator.isFQDN('example.com'); // true
isFQDNФункция поддерживает параметры, влияющие на строгую проверку:
validator.isFQDN('api.example.com', {
require_tld: true,
allow_underscores: false,
allow_numeric_tld: false,
allow_trailing_dot: false
});
require_tld
localhostallow_underscores
_allow_numeric_tld
allow_trailing_dot
example.com.Validator.js не предоставляет отдельной функции “isSubdomain”, поэтому используется логика анализа структуры.
const domain = 'api.v1.example.com';
const parts = domain.split('.');
Результат:
['api', 'v1', 'example', 'com']
function hasSubdomain(domain) {
const parts = domain.split('.');
return parts.length > 2;
}
hasSubdomain('example.com'); // false
hasSubdomain('api.example.com'); // true
isURLПри работе с URL часто требуется извлечь хост:
const validator = require('validator');
const url = 'https://api.example.com/users';
validator.isURL(url);
Современный способ — использовать встроенный URL:
const hostname = new URL('https://api.example.com/users').hostname;
// api.example.com
Далее применяется валидация:
validator.isFQDN(hostname);
Иногда требуется убедиться, что поддомен равен определённому значению.
function isApiSubdomain(url) {
const hostname = new URL(url).hostname;
return hostname.startsWith('api.');
}
isApiSubdomain('https://api.example.com'); // true
Для некоторых систем важно количество уровней:
example.com — основной доменapi.example.com — 1 уровень поддоменаv1.api.example.com — 2 уровняfunction getSubdomainDepth(domain) {
return domain.split('.').length - 2;
}
getSubdomainDepth('api.example.com'); // 1
getSubdomainDepth('v1.api.example.com'); // 2
Часто используется whitelist:
const allowed = ['api', 'admin', 'cdn'];
function isAllowedSubdomain(domain) {
const hostname = new URL(domain).hostname;
const sub = hostname.split('.')[0];
return allowed.includes(sub);
}
validator.isFQDN('localhost'); // false (при require_tld: true)
Для разработки:
validator.isFQDN('localhost', { require_tld: false });
validator.isFQDN('192.168.0.1'); // false
validator.isIP('192.168.0.1'); // true
validator.isFQDN('пример.рф');
Validator.js обрабатывает такие случаи через Punycode-представление:
'xn--e1afmkfd.xn--p1ai'
Иногда применяется ручная проверка:
const subdomainRegex = /^([a-z0-9-]+\.)+[a-z]{2,}$/i;
subdomainRegex.test('api.example.com');
Недостатки:
На практике используется связка:
function validateSubdomain(url) {
if (!validator.isURL(url)) return false;
const hostname = new URL(url).hostname;
if (!validator.isFQDN(hostname)) return false;
const parts = hostname.split('.');
return parts.length >= 3;
}
/api.example.com
/admin.example.com
Проверка:
const sub = new URL(req.url).hostname.split('.')[0];
client1.app.com
client2.app.com
function getTenant(url) {
return new URL(url).hostname.split('.')[0];
}
function isTrustedDomain(url) {
const hostname = new URL(url).hostname;
return validator.isFQDN(hostname) && hostname.endsWith('.example.com');
}
example.com // допустим
evil.example.com // тоже допустим без проверки уровня
validator.isFQDN('api.example.com/login'); // ошибка логики
Hostname нужно извлекать отдельно.
api.example.com.evil.com
Формально валидный домен, но логически другой. Поэтому важна проверка суффикса:
hostname.endsWith('.example.com')
function isValidSubdomain(url, rootDomain) {
if (!validator.isURL(url)) return false;
const hostname = new URL(url).hostname;
if (!validator.isFQDN(hostname)) return false;
return hostname === rootDomain || hostname.endsWith('.' + rootDomain);
}
Такой подход позволяет контролировать: