Полное руководство по разбору и кодированию URL: От структуры к безопасной обработке

Кодирование

Полная структура URL

https://user:pass@example.com:8080/path/to/page?name=value&age=25#section
  │       │     │    │          │  │   │            │                │
  scheme  user  pass  host      port path           query            fragment
Компонент Пример Описание
scheme https Протокол
userinfo user:pass Аутентификационные данные (редко используется)
host example.com Домен или IP
port 8080 Номер порта (по умолчанию 80/443)
path /path/to/page Путь
query ?name=value&age=25 Параметры запроса
fragment #section Якорь (не отправляется на сервер)

Разбор с помощью API URL

Базовый разбор

const url = new URL('https://example.com:8080/path?q=test#section');

url.protocol  // "https:"
url.hostname  // "example.com"
url.port      // "8080"
url.pathname  // "/path"
url.search    // "?q=test"
url.hash      // "#section"
url.origin    // "https://example.com:8080"
url.href      // Полный URL

Разбор параметров запроса

const url = new URL('https://example.com/api?name=Alice&age=25&tags=js&tags=css');

// URLSearchParams
url.searchParams.get('name')     // "Alice"
url.searchParams.get('age')      // "25"
url.searchParams.getAll('tags')  // ["js", "css"]
url.searchParams.has('name')     // true
url.searchParams.delete('age')

// Итерация
for (const [key, value] of url.searchParams) {
  console.log(`${key} = ${value}`);
}

Изменение URL

const url = new URL('https://example.com/page');

url.pathname = '/new-page';
url.searchParams.set('sort', 'desc');
url.searchParams.append('filter', 'active');
url.hash = '#top';

console.log(url.toString());
// "https://example.com/new-page?sort=desc&filter=active#top"

Правила URL-кодирования

Зачем нужно кодирование?

URL-адреса допускают только ASCII-символы, остальные символы должны быть закодированы:

Оригинал: https://example.com/search?q=你好 世界
Закодировано: https://example.com/search?q=%E4%BD%A0%E5%A5%BD%20%E4%B8%96%E7%95%8C

encodeURI vs encodeURIComponent

Функция Область кодирования Назначение
encodeURI Сохраняет структурные символы URL (:/?#[]@!$&'()*+,;=) Кодировать полный URL
encodeURIComponent Кодирует все не-ASCII + зарезервированные символы Кодировать значения параметров запроса
const url = 'https://example.com/path?name=你好&redirect=/home';

// encodeURI: сохраняет структуру URL
encodeURI(url);
// "https://example.com/path?name=%E4%BD%A0%E5%A5%BD&redirect=/home"

// encodeURIComponent: кодирует все специальные символы
encodeURIComponent(url);
// "https%3A%2F%2Fexample.com%2Fpath%3Fname%3D%E4%BD%A0%E5%A5%BD%26redirect%3D%2Fhome"

// ✅ Правильное использование: значения параметров с encodeURIComponent
const name = '你好 世界';
const redirect = '/home';
const fullUrl = `https://example.com/path?name=${encodeURIComponent(name)}&redirect=${encodeURIComponent(redirect)}`;

Общая таблица кодирования

Символ Кодирование Описание
Пробел %20 Не использовать + в URL
+ %2B В параметрах запроса + декодируется как пробел
& %26 Разделитель параметров запроса
= %3D Разделитель ключ-значение
# %23 Идентификатор якоря
% %25 Сам префикс кодирования
Китайский %E4%BD%A0 Трёхбайтовая кодировка UTF-8

Использование ToolsKu для кодирования/декодирования URL

  1. Откройте инструмент кодирования/декодирования URL
  2. Вставьте URL или текст в поле ввода
  3. Нажмите «Кодировать» или «Декодировать»
  4. Просмотрите результат

Безопасная обработка URL

1. Предотвращение URL-инъекций

// ❌ Опасно: прямая конкатенация пользовательского ввода
const url = `/api/users/${userId}`;

// ✅ Безопасно: валидация + кодирование
function buildUserUrl(userId) {
  if (!/^\d+$/.test(userId)) {
    throw new Error('Invalid user ID');
  }
  return `/api/users/${encodeURIComponent(userId)}`;
}

2. Предотвращение открытых перенаправлений

// ❌ Опасно: пользователь может указать любой URL перенаправления
app.get('/login', (req, res) => {
  res.redirect(req.query.redirect);
});

// ✅ Безопасно: валидация по белому списку
function safeRedirect(url, allowedHosts) {
  try {
    const parsed = new URL(url, 'https://example.com');
    if (allowedHosts.includes(parsed.hostname)) {
      return url;
    }
  } catch {
    // Недействительный URL
  }
  return '/'; // Перенаправление на главную страницу
}

3. Предотвращение XSS через URL

// ❌ Опасно: протокол javascript:
const url = 'javascript:alert(document.cookie)';

// ✅ Безопасно: разрешать только протоколы http/https
function sanitizeUrl(url) {
  try {
    const parsed = new URL(url);
    if (['http:', 'https:'].includes(parsed.protocol)) {
      return url;
    }
  } catch {
    // Недействительный URL
  }
  return 'about:blank';
}

API URLPattern (Новый стандарт)

// Сопоставление маршрутов
const pattern = new URLPattern({ pathname: '/api/users/:id' });

const result = pattern.exec('https://example.com/api/users/123');
if (result) {
  console.log(result.pathname.groups.id); // "123"
}

// Более сложный шаблон
const apiPattern = new URLPattern({
  protocol: 'https',
  hostname: ':env.example.com',
  pathname: '/api/:version/:resource/:id?',
});

const match = apiPattern.exec('https://prod.example.com/api/v2/users/456');
match.hostname.groups.env      // "prod"
match.pathname.groups.version  // "v2"
match.pathname.groups.resource // "users"
match.pathname.groups.id       // "456"

Лучшие практики построения параметров запроса

Использование URLSearchParams

// ✅ Рекомендуется: использовать URLSearchParams
const params = new URLSearchParams({
  q: '搜索关键词',
  sort: 'desc',
  page: '1',
  limit: '20',
});

params.append('tags', 'javascript');
params.append('tags', 'css');

const url = `https://api.example.com/search?${params}`;
// "https://api.example.com/search?q=...&sort=desc&page=1&limit=20&tags=javascript&tags=css"

Распространённые соглашения для параметров-массивов

Соглашение Пример Серверный фреймворк
Повторяющиеся ключи ?tags=js&tags=css Express, Koa
Суффикс с скобками ?tags[]=js&tags[]=css PHP, Rails
Индекс ?tags[0]=js&tags[1]=css PHP
Через запятую ?tags=js,css Пользовательский

Часто задаваемые вопросы

Почему пробел в URL иногда %20, а иногда +?

  • В пути URL: пробел = %20 (стандарт)
  • В параметрах запроса: пробел = + или %20 (+ — соглашение application/x-www-form-urlencoded)
  • Рекомендация: использовать %20 единообразно, избегая неоднозначности

Есть ли максимальный предел длины URL?

Сценарий Ограничение
Адресная строка Chrome 2МБ
Адресная строка Firefox Без ограничений
Адресная строка IE 2083 символа
HTTP GET-запрос Определяется сервером (обычно 8КБ)
Безопасный предел 2048 символов (совместимо со всеми браузерами)

Параметры, превышающие 2048 символов, должны использовать POST-запросы.


Итоги

URL — это фундамент Web; понимание его структуры, правил кодирования и безопасной обработки — базовый навык каждого разработчика. Ключевые моменты: кодировать значения параметров с encodeURIComponent, проверять протоколы для предотвращения XSS, валидировать по белому списку для предотвращения открытых перенаправлений. Инструмент кодирования/декодирования URL от ToolsKu поможет быстро решить проблемы кодирования URL.

#URL解析#URL编码#查询参数#Web开发#教程