Обработка 404 на сервере

В приложениях на Vue с использованием Vue Router часто возникает необходимость корректной обработки маршрутов, которые не существуют. Несмотря на клиентский роутинг, сервер также должен быть настроен так, чтобы возвращать правильный ответ при прямом обращении к несуществующему пути. Это особенно важно для SPA (Single Page Application), где клиентский роутинг управляет отображением компонентов, но сервер по умолчанию может возвращать ошибку 404.

Серверная настройка для SPA

Для корректной работы Vue Router необходимо настроить сервер так, чтобы все запросы на маршруты приложения возвращали один и тот же HTML-файл (index.html). Исключение составляют реальные статические ресурсы (например, изображения, CSS, JS-файлы). Это позволяет клиентскому приложению перехватывать маршруты и отображать соответствующие компоненты.

Пример конфигурации для разных серверов:

Nginx

server {
    listen 80;
    server_name example.com;

    root /var/www/my-app/dist;

    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}
  • $uri проверяет существование файла по запросу.
  • Если файл не найден, сервер возвращает index.html.
  • Это позволяет Vue Router обрабатывать маршруты на клиенте.

Apache

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
</IfModule>
  • !-f и !-d проверяют, что запрашиваемый файл или директория не существует.
  • Любой другой запрос перенаправляется на index.html.

Node.js с Express

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'dist')));

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});

app.listen(3000, () => {
  console.log('Server started on http://localhost:3000');
});
  • express.static обслуживает статические файлы.
  • Любой другой маршрут перенаправляется на index.html.

Настройка Vue Router для маршрута 404

На стороне клиента желательно иметь компонент для отображения ошибки 404. Для этого в routes добавляется универсальный маршрут:

import { createRouter, createWebHistory } from 'vue-router';
import Home from './components/Home.vue';
import NotFound from './components/NotFound.vue';

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: () => import('./components/About.vue') },
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;
  • /:pathMatch(.*)* перехватывает все маршруты, которые не были определены выше.
  • Такой маршрут должен идти последним, чтобы не перекрывать остальные.

Совмещение серверного и клиентского 404

  1. Сервер всегда возвращает index.html для несуществующих маршрутов, если это не статический ресурс.
  2. Vue Router обрабатывает путь и, если маршрут не найден, отображает компонент NotFound.
  3. Для API-запросов или ресурсов сервер должен корректно возвращать реальный 404 статус. Например:
app.get('/api/*', (req, res) => {
  res.status(404).json({ error: 'API endpoint not found' });
});
  • Это предотвращает конфликт с SPA-маршрутизацией.
  • Сервер различает запросы к фронтенду и запросы к API.

Дополнительные рекомендации

  • Для проектов с SSR (Server-Side Rendering) логика обработки 404 усложняется: необходимо возвращать корректный HTTP статус 404 при несуществующем маршруте.
  • Использование middleware на сервере позволяет централизованно обрабатывать ошибки 404, чтобы не дублировать код в каждом маршруте.
  • В Vue Router можно добавить глобальный beforeEach хук для логирования или аналитики попыток перехода на несуществующие страницы:
router.beforeEach((to, from, next) => {
  if (to.name === 'NotFound') {
    console.warn(`Попытка перехода на несуществующий маршрут: ${to.fullPath}`);
  }
  next();
});

Это позволяет вести статистику и улучшать UX, перенаправляя пользователей на актуальные страницы или показывая рекомендации.