function acceptsHtml(header, options) { //在这里 options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*']; for (var i = 0; i < options.htmlAcceptHeaders.length; i++) { if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) { return true; } } return false; }
前一段代码,如果 acceptsHtml 函数返回 false,说明浏览器不接受 html 文件,跳过执行 next(),否则继续执行。
后一段代码, acceptsHtml 函数内部设置 htmlAcceptHeaders 的默认值是 'text/html', '*/*' 。判断请求头的accept,如果匹配上说明返回true,否则返回false。直接用默认值接口不能正常返回 css 和 js, 改成 'text/html', 'application/xhtml+xml' 就能运行了。这就奇了怪了,htmlAcceptHeaders 为什么会影响 css 和 js。太晚了,不太想纠结了,简单粗暴把源码抠出来直接放到项目里面跑一下,看看到底发生了什么。
function acceptsHtml(header, options) { options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*']; console.log("header", header); console.log("htmlAcceptHeaders", options.htmlAcceptHeaders); for (var i = 0; i < options.htmlAcceptHeaders.length; i++) { console.log("indexOf", header.indexOf(options.htmlAcceptHeaders[i])); if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) { return true; } } return false; }
设置 htmlAcceptHeaders 值为 'text/html', 'application/xhtml+xml'
header text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 htmlAcceptHeaders [ 'text/html', 'application/xhtml+xml' ] indexOf 0 header text/css,*/*;q=0.1 htmlAcceptHeaders [ 'text/html', 'application/xhtml+xml' ] indexOf -1 indexOf -1
不设置 htmlAcceptHeaders
header text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 htmlAcceptHeaders [ 'text/html', '*/*' ] indexOf 0 header application/signed-exchange;v=b3;q=0.9,*/*;q=0.8 htmlAcceptHeaders [ 'text/html', '*/*' ] indexOf -1 indexOf 39
这时候我突然茅塞顿开,htmlAcceptHeaders 这个属性过滤 css 和 js 文件,如果用默认的 'text/html', '*/*' 属性,css 和 js 文件都会被匹配成 html 文件,然后一阵处理导致响应头的 mime 文件类型变成 text/html 导致浏览器无法解析。
原来不是写文档的人逻辑有问题,而是他是个懒人,不想解释太多,我是个蠢人不能一下子理解他的“深意”。
坑2
还有一点要注意,就是路由名称的设定。还是这个URL https://www.text.com/admin/login ,服务器把所有 /admin 的路由都指向了 vue 的 index.html 文件,hash模式下我们的路由这么配置的路由
const router = new VueRouter({ routes: [{ path: "/login", name: "login", component: login }] })
这时我们改成history模式
const router = new VueRouter({ mode: 'history', routes: [{ path: "/login", name: "login", component: login }] })
打开 url https://www.text.com/admin/login 会发现自动跳转到 https://www.text.com/login ,原因就是 /admin 的路由都指向了 vue 的 index.html 文件之后,js 根据我们的代码把url改成了 https://www.text.com/login ,如果我们不刷新页面没有任何问题,因为页面内所有的跳转还是 vue-router 控制, index.html 这个文件没变。但是如果刷新页面那就会出问题,服务器重新判断 /login 路由对应的文件。因此使用 history 模式时前端配置 vue-router 时也需要考虑后台的项目所在目录。
比如上面的例子应该改为,这样可以避免这种情况的问题
const router = new VueRouter({ mode: 'history', routes: [{ path: "/admin/login", name: "login", component: login }] })