connect-history-api-fallback是做什么的?
connect-history-api-fallbakc是一个用于Node.js服务器的中间件,特别是在使用express服务时,它的作用是支持单页应用程序(SPA)如Vue和React中的HTML5 History API。在SPA中,前端路由通常由js控制,而不是服务器上的实际文件路径,所以当用于直接访问一个非根目录的路由或者在非根目录刷新页面时,服务器会默认查找与该目录匹配的文件,但是显然这些文件并不存在,所以往往会导致404错误,connect-history-api-fallback中间件就是用来解决这个问题的,它可以默认将不匹配的路由重写到指定的索引文件,通常是index.html文件,这样就允许前端代码处理URL而不是返回404错误。
vue3项目部署到后端时如何用connect-history-api-fallback重写路由?
首先我们需要一个方法来区分哪些url是后端api那些是为了请求前端路由,一个比较好的方法是规定后端api的url都以“/api"开头,并将匹配这些api的中间件都放在connect-history-api-fallback中间件的前面,这样解析URL的时候凡是以"/api"开头的URL都会被前面的中间件捕获,而留到connect-history-api-fallback中间件的URL我们都认为这是在请求前端的路由,这样我们就可以将它重写到指定的索引文件(index.html),重写路由方法如下:
先引入中间件;
import history from "connect-history-api-fallback"
然后在所有捕获后端api中间件的最后面,添加:
app.use(history({
verbose:true
}))
其中verbose参数用于生成改写日志,方便调试时知道哪些URL被改写到了哪里
connect-history-api-fallback中间件默认的重写地址就是index.html,所以就不需要其他配置了,如果你需要自定义哪些路径需要被重写,其他路径保持原样,可以使用connect-history-api-fallback中间件的from...to...模式,例如:
app.use(history({
rewrites: [
{
from: /^\/libs\/.*$/,
to: function(context) {
return '/bower_components' + context.parsedUrl.pathname;
}
}
]
})
from接受一个正则表达式,用于匹配URL,to接受一个函数,函数的返回值就是改写后的路由,支持多组from...to...匹配,会由上往下依次匹配,且一个URL只会匹配一次。
最后我们要告诉express去哪里获取静态文件:
const __dirname = path.join(url,"../dist")
app.use(Express.static(__dirname))
这样express就知道在dist文件夹中去寻找静态资源。
代码示例:
import Express from "express";
import bodyParser from "body-parser";
import users from "./router/users.js"
import workflows from "./router/workflows.js"
import records from "./router/records.js"
import areas from "./router/areas.js";
import wxr from "./router/wx.js";
import departments from "./router/departments.js"
import roles from "./router/role.js";
import pages from "./router/page.js";
import path from 'path'
//引入connect-history-api-fallback中间件
import history from 'connect-history-api-fallback'
// 新建一个exprss服务
const app = Express();
app.use(bodyParser.json())
//后端api接口
app.use('/api/users',users)
app.use('/api/areas',areas)
app.use('/api/departments',departments)
app.use('/api/records',records)
app.use('/api/types',_types)
app.use('/api/roles',roles)
app.use('/api/pages',pages)
app.use('/api/wx',wxr)
//后端api接口未拦截的请求由connect-history-api-fallback中间件处理
app.use(history({
verbose:true
}));
//配置express获取静态文件的地址
const url = new URL(import.meta.url).pathname
const __dirname = path.join(url,'../dist')
app.use(Express.static(__dirname))
app.listen(3080,()=>{
console.log('listen 3080!')
})