Vue Router return 404 重访时 url
Vue Router return 404 when revisit to the url
我刚刚启用了 Vue 路由器历史记录模式。当我通过 v-href 或 href 访问 vue 路由时它工作正常。但是,当我尝试刷新该页面或直接从浏览器地址栏转到时,它只是 return 404。是否有接受 refresh/revisit 到 url 的选项?
以下是我的Vue路由配置
var router = new VueRouter({
hashbang: false,
history: true,
mode: 'html5',
linkActiveClass: "active",
root: '/user'
});
通过刷新页面,您正在使用当前 url 和服务器 returns 404 向服务器发出请求。您必须在 Web 框架或 Web 服务器级别处理此问题。
本文包含示例服务器配置:
https://router.vuejs.org/guide/essentials/history-mode.html
我认为您忽略了 SPA 不是服务器端渲染。至少对于大多数人来说。因此,当您访问 /anything 时,您的 Web 服务器不会将其重定向到 index.html。但是,如果您单击任何 vuejs 路由器 link,它将起作用,因为 javascript 起作用了,而不是服务器端。
要解决这个问题,请使用 .htaccess 并将所有请求重定向到 index.html,就像这样
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</ifModule>
希望对大家有所帮助!
如果有人在作为应用程序后端的 .NET Core 中处理这个问题,一个不错的方法是在我们的 .NET Core 应用程序的 Startup.cs 中使用一个简单的回退处理程序:
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 是这样实现的
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
}));
或使用本机节点
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)
})
两者都是 documentation 中的建议。
其他人也面临同样的问题,我才意识到
"book/:bookId/read" // this will not work after page reload
和这个不一样
"/book/:bookId/read" // this is what works even after page reload
这当然是在遵循其他人提出的建议之后,更重要的是在您的应用程序服务器端捕获所有路由。
我实际上不知道为什么会这样,但是任何有想法的人都可以告诉我们。
如果您真的不关心 url 中的散列,您可以在路由器配置文件中将模式设置为散列:mode: 'hash'
无需设置服务器端即可正常工作。
const router = new VueRouter({
routes: Routes,
mode: 'hash'
});
哈希模式在 vue 中是默认的,所以即使你留空而不是 mode: 'hash'
它也应该可以工作。
我将 Razor Pages 与 .net core 2.2 一起使用,我开始工作了:
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" });
});
对于 Netlify,将以下内容添加到 public/_redirects
文件...
/* /index.html 200
见https://www.netlify.com/docs/redirects/#history-pushstate-and-single-page-apps
来晚了,但是.....
如果有人对此有兴趣,我只是这样做了:
将对已知客户端 URL 的请求重定向到索引(但仅已知客户端 URL ,这样,您可以为实际页面保留 404 -未找到 URLs)。您如何执行此操作取决于您的服务器。我当时用的是flask,只是多加了路由而已
给根vue元素添加一个属性
<div id="content" redirect_to="{{redirect_to}}"></div>
我的视图函数将参数替换为 URL
请求的实际路线
- 在根 vue 组件中,检查此属性并检索其值,如下所示:
if (this.$el.attributes['redirect_to'].value !== "") path =
this.$el.attributes['redirect_to'].value
- 使用属性
的值调用$router.push
this.$router.push(path).catch(err => {})
(需要捕获,否则路由器将抛出 NavigationDuplicated 错误。)
我这样做是因为 SPA 中的整个 url 点是因为它们指向特定资源,我希望我的用户能够使用 URLs 返回到那些相同的资源。
希望这可以帮助某人或为他们指明正确的方向,使其能够满足他们的特定需求。
甚至更好(在 Ubuntu 上)如果你有 root 权限将修改 /etc/apache2/apache2.conf
,因为即使 Apache 自己 discourage 在这种情况下使用 .htaccess
.
请注意,首先,您必须做
sudo a2enmod rewrite
然后,将以下块添加到 /etc/apache2/apache2.conf
:
<Directory /var/www/html/>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
之后,做
sudo systemctl restart apache2
对我来说,这完美无缺,因为它不仅将 Vue 创建的路由重定向回 /
,而且实际上将网站刷新到相同的路由,所以刷新后你仍然在相同的视图中.
如果任何人在尝试上述解决方案后仍面临问题,请查找以下方法。
如果你有 vue.config.js
其中有
module.exports = {
publicPath: process.env.PUBLIC_URL || "", // <-- this is wrong
...
};
删除 vue.config.js 或尝试从导出对象中删除 publicPath。
如果您不想删除 publicPath,也可以尝试以下方法
module.exports = {
publicPath: process.env.PUBLIC_URL || "/", default)
transpileDependencies: ["vuetify"],
};
在我的案例中,它发生在 Azure CDN 下作为静态网站托管在 Azure Blob 存储中的 SPA 中。
以下问题的解决方案为我解决了这个问题(修复应用于 CDN 端点):
这太简单了,你只需要在你的服务器上添加这个配置:
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>
那么如果你在 Nginx:
location / {
try_files $uri $uri/ /index.html;
}
就这些了
有关详细信息,请访问此 Link
我也遇到了同样的问题。在路由中添加此代码后 -> web.php 问题已解决。
Route::get('/{vue_capture?}', function () {
return view('admin.dashboard');
})->where('vue_capture', '[\/\w\.-]*');
将此路线重定向到您的 parent blade 视图。
正如@SERPRO 所解释的那样,Vuejs、Angular、Reactjs 等都是基于单页应用程序 (SPA) 的概念构建的,所以我在 Apache 服务器上所做的只是告诉服务器为原点之后的任何路径值加载 index.html。以下是对我有用的更改。
在我的虚拟主机文件上,我添加了一个简单的重写规则以始终加载 index.html 而不是重定向。
RewriteEngine On
RewriteRule "^/auth/account/confirm" "/index.html"
因此,如果用户输入 http:///my-origin/account/confirm,服务器将加载绑定了 app.vue 文件的 index.html,以及 app.vue 文件路由器现在将选择路径 account/confirm 并确定要渲染的适当组件
然后运行
apachectl restart
service httpd restart
在我的例子中,404 错误不仅发生在页面重新加载时,也发生在使用浏览器的导航按钮时。
问题是路径中的特殊字符,如 ä、ö 等。首先,路由与那些工作得很好,但是当使用浏览器导航按钮或在页面上重新加载时,无法再找到该页面。在我用普通字母替换特殊字符后,路由再次起作用。
也许这对其他人有帮助。
就我而言,我使用 Vue 自己的配置来解决这个问题。这里的想法是利用 pages 选项。所以在文件 vue.config.js
中,我们将添加以下代码示例:
module.exports = {
pages: {
// This is our main page which refers to the main Javascript file
index: "src/main.js",
// Next, we list all other pages in the application,
// and let all of them refer to the main Javascript file as well.
other_page: "src/main.js",
},
};
使用此实现,如果我们停留在 other_page
并重新加载,应用程序仍然可以运行,不会显示任何 404 错误。
只需将代码放在同一文件夹中的 .htaccess 文件中即可。无需重启或 Apache 重启。
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
就我而言,我是通过虚拟主机处理的:
阿帕奇
转到 /etc/apache2/sites-available
并使用您的域名克隆 000-default.conf
即 app.abc.com.conf
并通过 sudo nano app.abc.com.conf
打开它然后放置在代码段下方:
Vue 文档参考:Click here
Whosebug 参考:
<VirtualHost *:80>
ServerName app.abc.com
DocumentRoot /var/www/html/project_name/dist/
ErrorLog ${APACHE_LOG_DIR}/app.abc.com.error.log
CustomLog ${APACHE_LOG_DIR}/app.abc.com.access.log combined
<Directory /var/www/html/project_name/dist>
FallbackResource /index.html
</Directory>
</VirtualHost>
Niginx Vue Cli (SPA) 虚拟主机:
Vue 文档参考:Click here
server {
listen 80;
root /var/www/html/project_name/dist;
server_name app.abc.com;
index index.html index.htm index.php;
location / {
try_files $uri $uri/ /index.html;
}
}
注意: 在 ubuntu 服务器上测试
我刚刚启用了 Vue 路由器历史记录模式。当我通过 v-href 或 href 访问 vue 路由时它工作正常。但是,当我尝试刷新该页面或直接从浏览器地址栏转到时,它只是 return 404。是否有接受 refresh/revisit 到 url 的选项?
以下是我的Vue路由配置
var router = new VueRouter({
hashbang: false,
history: true,
mode: 'html5',
linkActiveClass: "active",
root: '/user'
});
通过刷新页面,您正在使用当前 url 和服务器 returns 404 向服务器发出请求。您必须在 Web 框架或 Web 服务器级别处理此问题。
本文包含示例服务器配置: https://router.vuejs.org/guide/essentials/history-mode.html
我认为您忽略了 SPA 不是服务器端渲染。至少对于大多数人来说。因此,当您访问 /anything 时,您的 Web 服务器不会将其重定向到 index.html。但是,如果您单击任何 vuejs 路由器 link,它将起作用,因为 javascript 起作用了,而不是服务器端。
要解决这个问题,请使用 .htaccess 并将所有请求重定向到 index.html,就像这样
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</ifModule>
希望对大家有所帮助!
如果有人在作为应用程序后端的 .NET Core 中处理这个问题,一个不错的方法是在我们的 .NET Core 应用程序的 Startup.cs 中使用一个简单的回退处理程序:
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 是这样实现的
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
}));
或使用本机节点
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)
})
两者都是 documentation 中的建议。
其他人也面临同样的问题,我才意识到
"book/:bookId/read" // this will not work after page reload
和这个不一样
"/book/:bookId/read" // this is what works even after page reload
这当然是在遵循其他人提出的建议之后,更重要的是在您的应用程序服务器端捕获所有路由。 我实际上不知道为什么会这样,但是任何有想法的人都可以告诉我们。
如果您真的不关心 url 中的散列,您可以在路由器配置文件中将模式设置为散列:mode: 'hash'
无需设置服务器端即可正常工作。
const router = new VueRouter({
routes: Routes,
mode: 'hash'
});
哈希模式在 vue 中是默认的,所以即使你留空而不是 mode: 'hash'
它也应该可以工作。
我将 Razor Pages 与 .net core 2.2 一起使用,我开始工作了:
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" });
});
对于 Netlify,将以下内容添加到 public/_redirects
文件...
/* /index.html 200
见https://www.netlify.com/docs/redirects/#history-pushstate-and-single-page-apps
来晚了,但是.....
如果有人对此有兴趣,我只是这样做了:
将对已知客户端 URL 的请求重定向到索引(但仅已知客户端 URL ,这样,您可以为实际页面保留 404 -未找到 URLs)。您如何执行此操作取决于您的服务器。我当时用的是flask,只是多加了路由而已
给根vue元素添加一个属性
<div id="content" redirect_to="{{redirect_to}}"></div>
我的视图函数将参数替换为 URL
请求的实际路线- 在根 vue 组件中,检查此属性并检索其值,如下所示:
if (this.$el.attributes['redirect_to'].value !== "") path = this.$el.attributes['redirect_to'].value
- 使用属性 的值调用$router.push
this.$router.push(path).catch(err => {})
(需要捕获,否则路由器将抛出 NavigationDuplicated 错误。)
我这样做是因为 SPA 中的整个 url 点是因为它们指向特定资源,我希望我的用户能够使用 URLs 返回到那些相同的资源。
希望这可以帮助某人或为他们指明正确的方向,使其能够满足他们的特定需求。
甚至更好(在 Ubuntu 上)如果你有 root 权限将修改 /etc/apache2/apache2.conf
,因为即使 Apache 自己 discourage 在这种情况下使用 .htaccess
.
请注意,首先,您必须做
sudo a2enmod rewrite
然后,将以下块添加到 /etc/apache2/apache2.conf
:
<Directory /var/www/html/>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
之后,做
sudo systemctl restart apache2
对我来说,这完美无缺,因为它不仅将 Vue 创建的路由重定向回 /
,而且实际上将网站刷新到相同的路由,所以刷新后你仍然在相同的视图中.
如果任何人在尝试上述解决方案后仍面临问题,请查找以下方法。
如果你有 vue.config.js
其中有
module.exports = {
publicPath: process.env.PUBLIC_URL || "", // <-- this is wrong
...
};
删除 vue.config.js 或尝试从导出对象中删除 publicPath。
如果您不想删除 publicPath,也可以尝试以下方法
module.exports = {
publicPath: process.env.PUBLIC_URL || "/", default)
transpileDependencies: ["vuetify"],
};
在我的案例中,它发生在 Azure CDN 下作为静态网站托管在 Azure Blob 存储中的 SPA 中。
以下问题的解决方案为我解决了这个问题(修复应用于 CDN 端点):
这太简单了,你只需要在你的服务器上添加这个配置:
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>
那么如果你在 Nginx:
location / {
try_files $uri $uri/ /index.html;
}
就这些了
有关详细信息,请访问此 Link
我也遇到了同样的问题。在路由中添加此代码后 -> web.php 问题已解决。
Route::get('/{vue_capture?}', function () {
return view('admin.dashboard');
})->where('vue_capture', '[\/\w\.-]*');
将此路线重定向到您的 parent blade 视图。
正如@SERPRO 所解释的那样,Vuejs、Angular、Reactjs 等都是基于单页应用程序 (SPA) 的概念构建的,所以我在 Apache 服务器上所做的只是告诉服务器为原点之后的任何路径值加载 index.html。以下是对我有用的更改。 在我的虚拟主机文件上,我添加了一个简单的重写规则以始终加载 index.html 而不是重定向。
RewriteEngine On
RewriteRule "^/auth/account/confirm" "/index.html"
因此,如果用户输入 http:///my-origin/account/confirm,服务器将加载绑定了 app.vue 文件的 index.html,以及 app.vue 文件路由器现在将选择路径 account/confirm 并确定要渲染的适当组件
然后运行
apachectl restart
service httpd restart
在我的例子中,404 错误不仅发生在页面重新加载时,也发生在使用浏览器的导航按钮时。
问题是路径中的特殊字符,如 ä、ö 等。首先,路由与那些工作得很好,但是当使用浏览器导航按钮或在页面上重新加载时,无法再找到该页面。在我用普通字母替换特殊字符后,路由再次起作用。
也许这对其他人有帮助。
就我而言,我使用 Vue 自己的配置来解决这个问题。这里的想法是利用 pages 选项。所以在文件 vue.config.js
中,我们将添加以下代码示例:
module.exports = {
pages: {
// This is our main page which refers to the main Javascript file
index: "src/main.js",
// Next, we list all other pages in the application,
// and let all of them refer to the main Javascript file as well.
other_page: "src/main.js",
},
};
使用此实现,如果我们停留在 other_page
并重新加载,应用程序仍然可以运行,不会显示任何 404 错误。
只需将代码放在同一文件夹中的 .htaccess 文件中即可。无需重启或 Apache 重启。
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
就我而言,我是通过虚拟主机处理的:
阿帕奇
转到 /etc/apache2/sites-available
并使用您的域名克隆 000-default.conf
即 app.abc.com.conf
并通过 sudo nano app.abc.com.conf
打开它然后放置在代码段下方:
Vue 文档参考:Click here
Whosebug 参考:
<VirtualHost *:80>
ServerName app.abc.com
DocumentRoot /var/www/html/project_name/dist/
ErrorLog ${APACHE_LOG_DIR}/app.abc.com.error.log
CustomLog ${APACHE_LOG_DIR}/app.abc.com.access.log combined
<Directory /var/www/html/project_name/dist>
FallbackResource /index.html
</Directory>
</VirtualHost>
Niginx Vue Cli (SPA) 虚拟主机:
Vue 文档参考:Click here
server {
listen 80;
root /var/www/html/project_name/dist;
server_name app.abc.com;
index index.html index.htm index.php;
location / {
try_files $uri $uri/ /index.html;
}
}
注意: 在 ubuntu 服务器上测试