History API и hash-routing

History API и hash-routing — два механизма клиентской навигации в SPA: первый меняет URL через pushState без перезагрузки, второй использует якорь (#) в URL для хранения маршрута.

Зачем нужно

Любой SPA-роутер строится поверх одного из этих механизмов. Понимание разницы объясняет, почему react-router предлагает BrowserRouter (History API) и HashRouter (hash-routing), в каких ситуациях каждый из них применим и как настроить сервер для корректной работы.

Где используется

  • History API / BrowserRouter: большинство современных SPA на хостингах с поддержкой fallback (Vercel, Netlify, Nginx с try_files)
  • HashRouter: статические хостинги без server-side роутинга (GitHub Pages, S3 без CloudFront)
  • MemoryRouter (react-router): тестирование и React Native — нет URL вообще

History API

// pushState — добавляет запись в историю
// history.pushState(state, title, url)
history.pushState({ page: 'about' }, '', '/about');

// replaceState — заменяет текущую запись
history.replaceState({ page: 'home' }, '', '/');

// Навигация назад/вперёд
history.back;
history.forward;
history.go(-2); // на 2 шага назад

// Событие при кнопках Назад/Вперёд
window.addEventListener('popstate', (event) => {
  console.log('Путь изменился:', window.location.pathname);
  console.log('State:', event.state);
  // Перерендерить компонент для нового пути
  renderPage(window.location.pathname);
});

BrowserRouter (react-router)

import { BrowserRouter, Routes, Route, Link, useNavigate } from 'react-router-dom';

function App() {
  return (
    // BrowserRouter использует History API под капотом
    <BrowserRouter>
      <nav>
        <Link to="/">Главная</Link>
        <Link to="/about">О нас</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users/:id" element={<UserProfile />} />
      </Routes>
    </BrowserRouter>
  );
}

Hash-routing

Hash (#) в URL не отправляется на сервер — браузер обрабатывает его полностью на клиенте:

https://example.com/#/about
https://example.com/#/users/42
// Изменение hash
window.location.hash = '#/about';

// Событие при изменении hash
window.addEventListener('hashchange', () => {
  const path = window.location.hash.slice(1); // убираем '#'
  renderPage(path);
});

// Получить текущий маршрут
const currentPath = window.location.hash.slice(1) || '/';

HashRouter (react-router)

import { HashRouter } from 'react-router-dom';

// URL будет выглядеть как: example.com/#/about
// Подходит для GitHub Pages и других статических хостингов
function App() {
  return (
    <HashRouter>
      {/* ... */}
    </HashRouter>
  );
}

Сравнение

Критерий History API Hash-routing
URL /about /#/about
SEO Хорошее Плохое (# игнорируется)
Настройка сервера Нужен fallback Не нужна
Поддержка браузеров IE10+ Все браузеры
Аналитика Нативная Требует настройки

Nginx fallback для History API

# nginx.conf
location / {
  try_files $uri $uri/ /index.html;
}

Частые ошибки

  • Не настроен server fallback для History API — при прямом заходе на /about сервер возвращает 404, потому что файла about нет; нужно настроить редирект на index.html.
  • Используют HashRouter для SEO-важных страниц — поисковики плохо индексируют hash-URL.
  • Не обрабатывают popstate — кнопки «Назад»/«Вперёд» не работают в самописном роутере.

Связанные темы

Ресурсы