Перенаправление Vue-router на странице не найдено (404)

Я пытаюсь без особого успеха выполнить перенаправление на 404.html на странице, не найденной с помощью глобального хука router.beforeEach (с использованием Vueи Vue-Router 1.0):

router.beforeEach(function (transition) {
    if (transition.to.path === '/*') {
        window.location.href = '/404.html'
    } else {
        transition.next()
    }
});

Это не перенаправление на страницу 404.html, когда вставлен несуществующий маршрут, а просто дает мне пустой фрагмент. Только при жестком кодировании some-site.com/* он будет перенаправлен на ожидаемый some-site.com/404.html

Я уверен, что здесь есть что-то очень очевидное, что я не замечаю, но я не могу понять, что именно.


Обратите внимание, что я ищу перенаправление на новую страницу, а не перенаправление на другой маршрут, чего можно легко добиться, используя router.redirect, например, в этих фрагментах:

router.redirect({
    '*': '404'
})

А на моем router.map у меня могло быть следующее:

 router.map({
    '/404': {
        name: '404'
        component: {
            template: '<p>Page Not Found</p>'
        }
    }
})

person nunop    schedule 22.10.2016    source источник
comment
У меня пока нет решения, но что произойдет, если вы попытаетесь перейти к маршруту с использованием тега <a>, который не обрабатывается маршрутизатором Vue? Выходит ли он из приложения?   -  person Mani    schedule 22.10.2016
comment
Он перейдет к ожидаемому маршруту независимо от того, использую ли я href или v-link (например, href = some-site .com / home вместо v-link = {name: 'home'}). Не уверен, что это то, о чем вы спрашиваете?   -  person nunop    schedule 22.10.2016
comment
Приношу свои извинения, я думал о том, как полностью выйти из приложения, даже когда у нас есть <base href="/">. В любом случае это не имело отношения к вашему вопросу. Я опубликовал свои мысли в качестве ответа ниже, попробуйте и дайте мне знать, работает ли это!   -  person Mani    schedule 22.10.2016


Ответы (5)


Я думаю, вы должны иметь возможность использовать обработчик маршрута по умолчанию и перенаправлять оттуда на страницу за пределами приложения, как подробно описано ниже:

const ROUTER_INSTANCE = new VueRouter({
    mode: "history",
    routes: [
        { path: "/", component: HomeComponent },
        // ... other routes ...
        // and finally the default route, when none of the above matches:
        { path: "*", component: PageNotFound }
    ]
})

В приведенном выше определении компонента PageNotFound вы можете указать фактическое перенаправление, которое полностью выведет вас из приложения:

Vue.component("page-not-found", {
    template: "",
    created: function() {
        // Redirect outside the app using plain old javascript
        window.location.href = "/my-new-404-page.html";
    }
}

Вы можете сделать это либо на created, как показано выше, либо также на mounted.

Пожалуйста, обрати внимание:

  1. Я не проверял вышеизложенное. Вам необходимо создать производственную версию приложения, убедитесь, что происходит указанное выше перенаправление. Вы не можете проверить это в vue-cli, так как это требует обработки на стороне сервера.

  2. Обычно в одностраничных приложениях сервер отправляет один и тот же index.html вместе со сценариями приложения для всех запросов маршрута, особенно если вы установили <base href="/">. Это не удастся для вашего /404-page.html, если ваш сервер не будет рассматривать его как особый случай и не будет обслуживать статическую страницу.

Сообщите мне, если это сработает!

Обновление для Vue 3 и более поздних версий:

Вам нужно будет заменить свойство '*' path на '/:pathMatch(.*)*', если вы используете Vue 3, поскольку старый универсальный путь '*' больше не поддерживается. Тогда маршрут будет выглядеть примерно так:

{ path: '/:pathMatch(.*)*', component: PathNotFound },

Дополнительную информацию см. В документации. в этом обновлении.

person Mani    schedule 22.10.2016
comment
Я думаю, что реальным ответом была обработка на стороне сервера, как подробно описано в разделе «Обратите внимание» выше. Ваш router.beforeEach делает то же самое, что и в моем методе. Вашему серверу просто необходимо обрабатывать 404.html как особый случай, который вы можете протестировать только на реальном сервере, а не vue-cli. - person Mani; 22.10.2016
comment
Ваше решение сработало отлично, большое вам спасибо! Также благодарю вас за подсказку относительно обработки на стороне сервера с router.beforeEach. Я использую локальную машину (vagrant + virtualbox) с nginx. Я поиграю с конфигурацией и посмотрю, смогу ли я найти решение на стороне сервера. - person nunop; 22.10.2016
comment
Как Vue Router 2.2.0, я использую path: '*' в определении маршрутизатора для перехвата всех неопределенных маршрутов, как указано в документы - person Andre Ravazzi; 18.04.2020

Ответ @mani теперь немного устарел, поскольку использование универсальных '*' маршрутов - это больше не поддерживается при использовании Vue 3 и более поздних версий. Если это больше не работает для вас, попробуйте заменить старый универсальный путь на

{ path: '/:pathMatch(.*)*', component: PathNotFound },

По сути, вы должны иметь возможность заменить путь '*' на '/:pathMatch(.*)*' и готово!

Причина: Vue Router больше не использует path-to-regexp, вместо этого он реализует собственную систему синтаксического анализа, которая позволяет ранжировать маршруты и активировать динамическую маршрутизацию. Поскольку мы обычно добавляем один универсальный маршрут для каждого проекта, поддержка специального синтаксиса для *.

(из https://next.router.vuejs.org/guide/migration/#removed-star-or-catch-all-routes)

person Luca C    schedule 03.10.2020
comment
Как насчет того, чтобы просто заменить его на (.*)*, поскольку :pathMatch будет просто параметром, которому назначено совпадение, правильно? Так что это могло быть { path: '/:thisIsMyCustomErrorCatchAll(.*)*', component: PathNotFound },. Я просмотрел документы, чтобы подтвердить, и не нашел ничего, что могло бы противоречить этому. next.router. vuejs.org/guide/essentials/ - person redfox05; 08.03.2021

Оригинальный ответ @mani - это все, что вам нужно, но если вы также хотите прочитать его официальным способом, вот

Ссылка на официальную страницу Vue:

https://router.vuejs.org/guide/essentials/history-mode.html#caveat

person Qback    schedule 27.11.2018

Этот ответ может быть немного запоздалым, но я нашел приемлемое решение. Мой подход немного похож на подход @Mani, но я думаю, что мой подход немного легче понять.

Помещение его в глобальную ловушку и в сам компонент не идеально, глобальная ловушка проверяет каждый запрос, поэтому вам нужно будет написать множество условий, чтобы проверить, должно ли оно быть 404 и window.location.href при создании компонента слишком поздно, поскольку запрос ушел уже в компонент, а затем вынимаете его.

Я создал специальный URL-адрес для страниц 404 и путь * для всего, что не найдено.

{ path: '/:locale/404', name: 'notFound', component: () => import('pages/Error404.vue') },
{ path: '/:locale/*', 
  beforeEnter (to) {
    window.location = `/${to.params.locale}/404`
  }
}

Вы можете игнорировать :locale, поскольку мой сайт использует i18n, чтобы я мог убедиться, что страница 404 использует правильный язык.

Кстати, я хочу убедиться, что моя страница 404 возвращает код состояния httpheader 404 вместо 200, когда страница не найдена. Приведенное выше решение просто отправит вас на страницу 404, но вы по-прежнему получаете код состояния 200. Для этого у меня есть правило nginx, чтобы возвращать код статуса 404 для местоположения /:locale/404

server {
    listen                      80;
    server_name                 localhost;

    error_page  404 /index.html;
    location ~ ^/.*/404$ {
      root   /usr/share/nginx/html;
      internal;
    }

    location / {
      root   /usr/share/nginx/html;
      index  index.html index.htm;
      try_files $uri $uri/ @rewrites;
    }

    location @rewrites {
      rewrite ^(.+)$ /index.html last;
    }

    location = /50x.html {
      root   /usr/share/nginx/html;
    }
}
person Alan Ho    schedule 30.06.2020
comment
Проблема с этим приводит к коду состояния 200 для страницы 404, что неприемлемо с точки зрения SEO. Может ли кто-нибудь подсказать, как установить код состояния 404 в VueJS для страницы 404? - person Jenil Kanani; 08.12.2020

Не используйте редирект, используйте beforeEnter

  const  router = [


  // { path: '*', redirect: '/404'},
  { path: '*', beforeEnter: (to, from, next) => { next('/404') } },
  {
    path: '/404',
    name: '404',
    component: () => import('@/views/404')
  }
]
person anson    schedule 22.07.2021
comment
Не могли бы вы немного расширить, почему так лучше? - person nunop; 23.07.2021