404 单页应用 报错 路由_单页应用history路由改造

需求

调用其它团队流量站埋点统计时会截取锚点#,导致单页应用分页面流量分析获取不到数据。而本项目迫切需要按菜单、特殊功能模块统计流量情况,等不及流量站的团队开发升级版,于是选择改造项目路由为hostory模式。

单页应用路由实现思路

SPA,只加载一个HTML,页面在用户与应用程序交互时动态更新该页。即理论上来说,只需加载一次页面就可以不再请求(首屏耗时过长需按模块chunk,预加载css,按需加载js),当点击其他子页面时只会有相应的URL改变而不会重新加载。

这种情况下实现路由的过程分为两部分:

更新URL页面不刷新

URL变化时执行页面替换逻辑

现在主流有2种实现方式:

history.pushState等触发popstate事件

location.hash的变化触发hashchange事件

vue-router中提供了三种方式HTML5History(判断是否支持)、HashHistory、AbstractHistory(用于Node环境,因为不涉及和浏览器地址相关记录关联在一起;整体流程依旧和 HashHistory 是一样的,只是这里通过数组来模拟浏览器历史记录堆栈信息)

默认为Hash模式,组件(components)映射到路由(routes),registerHook设置守卫入栈,在每次跳转的时候,递归守卫集合,将触发的守卫进行解析和执行。

实现过程 & 踩坑记录

1. Router传入配置项,设置mode为'history'

export default new Router({ mode: 'history', routes })

2. 开发模式下,webpack 热启动配置 history 模式

webpack属性中historyApiFallback默认能将当前找不到的目录重定向到主目录默认index.html。

在 webpack 配置文件的devServer配置,将url重写到自己配置的目录:

// webpack.dev.conf.js

devServer: {

...

historyApiFallback: {

rewrites: [

{ from: /.*/, to: '/index.html' }

],

},

...

}

3. 部署预发后,刷新时资源404

开发过程一切正常,直到编译打包发布。

状况:从域名点击菜单能正常跳转,但刷新当前页会报错404。(Eg:从test.com点击访问/111正常,但直接访问test.com/111报404)

原因:在History mode下,直接通过地址栏访问url会被http server直接解析到该文件路径,但是spa的路由是虚拟的,并不能直接找到这个file,所以会404。

解决思路:如果URL匹配不到任何静态资源,就跳转到默认的index.html,让router去解析url, nginx中需要配置try_files。

# 当前项目使用了第一级'/'来区分产品,所以这里匹配metric、stocktake

# 一般直接'location ~ /'即可

location ~ ^(/metric|/stocktake) {

try_files $uri $uri/ /index.html;

}

具体配置官方提供了:其它服务器配置

4. 页面不再404,开始报语法错误

报错如下

DOM情况:

资源情况:

原因:修改为history模式后,相对定位不再适用,资源会根据当前刷新路径变更访问路径(注意上图资源情况访问的文件夹)。在此项目中静态资源vendor.dll.的引入路径有问题,需将相对路径'./'修改为绝对路径'/'

5. 页面正常加载,但后端接口被统一重定向

原因:step3时在nginx处配置了try_files 加上后端接口也是/metric、/stocktake开头。于是就不幸地被nginx匹配到规则统一作跳转处理了。

解决:区分接口与页面。在项目中统一对后端接口加'/api/',nginx新建规则匹配'/api/'并作相应跳转。

// 在发请求的公共方法处添加'/api/'

function ajax(url, type, params, opt = '') {

return Q.Promise((resolve, reject) => {

const config = {

method: type === 'get' ? 'get' : 'post',

// TODO: '/api/'暂时作为nginx区分重定向的匹配字段 待与兆华协商统一 不与路由命名重复

url: C.HOST + '/api/' + url,

params: type === 'get' ? params : null,

data: configData(type, params, opt)

}

axios(config).then(checkStatus).then(checkCode).then((response) => {

resolve(response)

}).catch((err) => {

console.log(err)

if (err.msg) Notice(err.msg)

reject(err)

})

})

}

nginx中添加如下匹配规则并重写url

```

# 后台三类开头对应请求不同服务器

location ~ ^/api/system/ {

rewrite ^/api/(.*) /$1 break;

proxy_pass http://assets-api-yf.jd.com;

proxy_redirect off;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

location ~ ^/api/metric/ {

rewrite ^/api/(.*) /$1 break;

proxy_pass http://metrics-api-yf2.jd.com;

proxy_redirect off;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

location ~ ^/api/stocktake/ {

rewrite ^/api/(.*) /$1 break;

proxy_pass http://meta-api-yf.jd.com;

proxy_redirect off;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

```

6. 切换产品菜单时会刷新

因为使用的是window.location,替换成this.$router.push即可

7. 非法输入路由时,未正常重定向到首页,直接404

状况:地址栏输入test.com/ffsdfdsge,显示'404 Not Found',并未重定向到首页。

解决:nginx配置error_page。

server {

...

error_page 404 /index.html;

...

}

前端小菜鸟一枚,如表述有误,恳请各位大神指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值