通过Nginx,代理Vue项目,刷新页面返回404,思考VUE项目的F5刷新和路由请求。
通过Nginx,代理Vue项目,刷新页面返回404。
为什么会出现404
原因是因为web单页面开发模式,只有一个index.html入口,其他路径是前端路由去跳转的,nginx没有对应这个路径,当然就是404了。
一般nginx监听配置如下
server {
listen 8086;
server_name localhost;
location / {
root D:\XXX\XXX\dist;
index index.html index.htm;
}
}
知道是因为nginx找不到路径那么该如果去处理
处理方法
在配置中加上try_files,意思跟翻译差不多,“尝试读取文件”。
server {
listen 8086;
server_name localhost;
location / {
root D:\XXX\XXX\dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
当用户请求 http://localhost/example
时,这里的 $uri
就是 /example
。
try_files 会到硬盘里尝试找这个文件。如果存在名为 /$root/example
(其中 $root
是项目代码安装目录)的文件,就直接把这个文件的内容发送给用户。
显然,目录中没有叫 example 的文件。然后就看 $uri/
,增加了一个 /
,也就是看有没有名为 /$root/example/
的目录。
又找不到,就会 fall back 到 try_files 的最后一个选项 /index.php,发起一个内部 “子请求”,也就是相当于 nginx 发起一个 HTTP 请求到 http://localhost/index.php
。
那么为什么VUE项目会出现这个问题?
前言
基于vue-cli脚手架开发的单页应用有他特殊的特点和优势。因为是单页应用,所以在进行F5刷新的时候和之前常规的html页面还有区分。主要区别在于,vue-router接管了浏览器的前进、后退、刷新等事件,通过对相关事件的监听,动态的操作popstate,pushstate,replacestate等api来完成浏览器url的变化;但其实对于页面本身而言,并没有我们所理解的常规刷新或者后退前进操作,毕竟是单页应用,内部的核心还是动态的div切换或者dom元素的动态渲染。
本篇通过对F5刷新操作的跟踪,我们来记录和了解一下vue组件是如何对对刷新操作进行处理的,各个组件的生命周期又是如何进行操作的,又有哪些点是需要我们注意的。
问题描述
我们先来看一个具体的问题,实际项目中,登录成功之后的页面是一个左右结构的页面,假设为组件A,左侧是菜单区域,右侧是显示区域,我们的做法是在右侧区域添加一个<router-view>,通过左侧菜单的点击,动态的改变右侧router-view中的页面效果。首次登陆成功之后,要显示一个默认页面,我们在组件A的create中获取菜单树,然后判断菜单的id是否顶级,如果是则自动显示,假设默认组件是B。然后选择左侧菜单,跳转新页面,右侧区域渲染,假设我们显示了C组件,此时F5刷新,页面会自动回到组件B,也就是说,刷新操作无法刷“当前页”,只要刷新总会返回首页。
问题分析
我们在根组件A的beforeRouteEnter钩子函数中将to、from打印出来。然后我们通过左侧菜单点击,页面跳转到manager_device_list路由页面,然后点击F5刷新,打印的to 和 from如下
可以看到from的null,to就是我们当前的路由页面,但是为何会自动跳转到首页B去了呢?
这里就要说一下F5刷新时候组件的生命周期。
F5刷新的时候,会从跟组件重新走生命周期,即其实是从root.vue开始重新走声明周期,然后一级一级往下走,根据to路由最终到具体的渲染页面,问题就是出在这里,因为我们在跟组件A的create方法中循环菜单并自动跳转到首页了,所以在F5之后重新走跟组件声明周期时,在create中直接就把路由改变了,而不会再回到原来的to。
问题解决
通过再跟组件A的beforeRouteEnter钩子函数中判断from.name是否为null,来操作是否走自动到首页的逻辑。相关代码如下:
beforeRouteEnter(to, from, next) {
console.log("to--->",to);
console.log("from--->",from);
if(ctool.strIsEmpty(from.name)){
next();
}else{
next(vm => vm.initViews());
}
},
这里initViews中就是循环菜单找到首页并跳转到首页的逻辑。通过上面这种处理,完美解决该问题。
总结
(1) 不管是在浏览器中还是通过this.$router.push跳转某个页面时候,路由都是会从跟组件开始走,最终定位到具体的子组件,并在其对应的router-view中渲染,尤其是router-view嵌套router-view时候会看的更清晰,子组件始终是在父组件的生命周期走完再开始渲染。即:如果出现刷新后,页面没有留在当前页,那肯定是代码逻辑处理的有问题。
(2) F5刷新操作会清空store中的数据,所以般情况下,我们可以通过监听浏览器的刷新事件,在跟组件中对store中的数据通过localstorage进行保存和还原。
- 点赞
- 收藏
- 关注作者
评论(0)