关于vue.js:当重新访问URL时,Vue Router返回404

Vue Router return 404 when revisit to the url

我只是启用Vue路由器历史记录模式。 当我通过v-href或href访问vue路由时,它工作正常。 但是,当我尝试刷新该页面或直接从浏览器地址栏进入时,它仅返回404。是否有任何选项可以接受刷新/重新访问该URL?

以下是我的Vue路由器配置

1
2
3
4
5
6
7
var router = new VueRouter({
    hashbang: false,
    history: true,
    mode: 'html5',
    linkActiveClass:"active",
    root:  '/user'
});

通过刷新页面,您正在使用当前URL向服务器发出请求,并且服务器返回404。您必须在Web框架或Web服务器级别上处理此问题。

https://router.vuejs.org/en/essentials/history-mode.html


我认为您错过了SPA不是服务器端渲染的问题。至少对于大多数人来说。因此,当您访问/ anything时,您的网络服务器不会将其重定向到index.html。但是,如果您单击任何vuejs路由器链接,由于javascript起作用了,而不是服务器端,因此它将起作用。

要解决此问题,请使用.htaccess并将所有请求重定向到index.html,如下所示

1
2
3
4
5
6
7
8
<ifModule mod_rewrite.c>
    RewriteEngine On
  RewriteBase /
  RewriteRule ^index\\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</ifModule>

希望它能对某人有所帮助!


如果您不太在乎url中的哈希,则可以将模式设置为在路由器配置文件中哈希:mode: 'hash'
无需设置服务器端即可正常工作。

1
2
3
4
const router = new VueRouter({
    routes: Routes,
    mode: 'hash'
});

哈希模式在vue中默认为默认模式,因此即使您保留空白而不是mode: 'hash',它也应能正常工作。


如果有人将.NET Core作为应用程序的后端处理此问题,则一种不错的方法是.NET Core应用程序的Startup.cs中的简单后备处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
        ....Your configuration
      app.UseMvc(routes =>
      {
        routes.MapRoute(
                  name:"default",
                  template:"{controller=Home}/{action=Index}/{id?}");
      });
      //handle client side routes
      app.Run(async (context) =>
      {
        context.Response.ContentType ="text/html";
        await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));
      });
    }
 }

有关更多详细信息:http://blog.manuelmejiajr.com/2017/10/letting-net-core-handle-client-routes.html


对于使用Express后端看到此消息的人,中间件connect-history-api-fallback的实现方式如下

1
2
3
4
5
6
7
const express = require('express');
const history = require('connect-history-api-fallback');

const app = express();
app.use(history({
  index: '/' //whatever your home/index path is default is /index.html
}));

或与本机节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const http = require('http')
const fs = require('fs')
const httpPort = 80

http.createServer((req, res) => {
  fs.readFile('index.htm', 'utf-8', (err, content) => {
    if (err) {
      console.log('We cannot open"index.htm" file.')
    }

    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8'
    })

    res.end(content)
  })
}).listen(httpPort, () => {
  console.log('Server listening on: http://localhost:%s', httpPort)
})

两者都是文档中的建议。


如果您具有root用户访问权限,那么最好在Ubuntu上修改/etc/apache2/apache2.conf,因为在这种情况下,即使Apache本身也不鼓励使用.htaccess

请注意,首先,您必须

1
sudo a2enmod rewrite

然后,将以下块添加到/etc/apache2/apache2.conf

1
2
3
4
5
6
7
8
<Directory /var/www/html/>
        RewriteEngine On
        RewriteBase /
        RewriteRule ^index\\.html$ - [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.html [L]
</Directory>

之后,做

1
sudo systemctl restart apache2

对我来说,这是完美无缺的,因为它不仅将Vue创建的路由重定向回/,而且实际上将网站刷新为相同的路由,因此刷新后您仍处于相同的视图。


迟到了,但是.....

如果有人对此感兴趣,请执行以下操作:

  • 将对已知客户端URL的请求重定向到索引(但只有已知的客户端URL,这样,您才可以为实际的页面未找到的URL保留404)。您如何执行此操作取决于您的服务器。我当时使用的是Flask,只是添加了更多路线。

  • 向根vue元素添加属性

  • 1
     

    我的视图函数将参数替换为URL请求的实际路由的地方

  • 在root vue组件中,检查该属性并检索其值,如下所示:
  • if (this.$el.attributes['redirect_to'].value !=="") path =
    this.$el.attributes['redirect_to'].value

  • 使用属性的值调用$ router.push
  • this.$router.push(path).catch(err => {})

    (需要catch,否则路由器将引发NavigationDuplicated错误。)

    之所以这样做,是因为SPA中的URL的全部要点是因为它们指向特定的资源,所以我希望我的用户能够使用URL来返回相同的资源。

    希望这可以帮助某人或为他们指明正确的方向,使其适合他们的特定需求。


    对于Netlify,将以下内容添加到public/_redirects文件中...

    1
    /*    /index.html   200

    参见https://www.netlify.com/docs/redirects/#history-pushstate-and-single-page-apps


    我正在将Razor Pages与.net core 2.2一起使用,并且可以正常工作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name:"default",
                    template:"{controller}/{action=Index}/{id?}");

                routes.MapRoute(
                    name:"spa-fallback",
                    template:"{*url:regex(^((?!.css|.map|.js|sockjs).)*$)}",
                    defaults: new { controller ="Index", action ="Index" });

            });

    其他人遇到同样的问题,我才意识到

    1
    "book/:bookId/read"  // this will not work after page reload

    这是不同的

    1
    "/book/:bookId/read" // this is what works even after page reload

    当然,这是在遵循其他向导提出的建议之后,更重要的是在您的应用服务器端捕获所有路由。
    我实际上不知道为什么这样做,但是任何有任何想法的人都可以告诉我们。