现象:
- 本地调试(同源请求)发现,接口返回404
- 测试环境 (跨域请求) 发现报cors跨域错误
- 部分接口能请求成功,部分接口请求失败(404或跨域报错)
原因
为什么返回404
中间件参数中有个next函数,需要使用await调用,若省略await,且接口函数是异步的,会直接返回,而没有真正执行到接口函数
,ctx的response默认内容就是404,所以同源请求会返回404
为什么配置了跨域还会跨域报错呢?
这是因为,跨域时会发起preflight请求(预检请求),preflight请求成功即认为允许跨域,否则报跨域错误,并且preflight只允许2xxx返回码,重定向返回3xx也会认为是错误;
我后台配置了https,并且设置了自动将http请求重定向至https,而前端是用http请求的,所以返回了302重定向,preflight认为失败了,所以会报cors错误
为什么部分接口成功,部分失败
如果接口函数是同步执行的,那么用不用await都是没有影响的,所以同步执行的接口函数都会成功,而异步执行的都会失败
分析过程
- F12查看网络请求状态,发现有一个明明注册了路由的接口返回了404,而其他部分接口却返回了正常
- 因为最新的改动就是增加了该接口,并且添加了中间件,尝试去除中间件,发现接口可以正常访问
- 通过打log发现,中间件逻辑是正常的,没有问题
- 详细查log发现,接口是可以请求到一次的(preflight请求,正式请求会报cors),但是接口返回的结果依然是404
- 反应过来,ctx的response默认status就是404,猜测是不是body没填充,然后想起来,next其实就是调用新写的接口,新写的接口是异步的,next直接调用能不能执行异步逻辑呢,显然是不行的,尝试加上await后,一切恢复正常
中间件内容
export default (/*options: any, app: Application*/) => {
return async function auth(ctx :Context, next) {
const token = ctx.header.authorization as string;
const user: User |undefined = await G.userMgr.getUserByToken(token);
const isLogin = user !== undefined && !user.needRelogin();
if(!isLogin && ctx.request.url.indexOf('/user/login') == -1) {
ctx.body = "not login";
return;
}
ctx.user = user;
ctx.token = token;
ctx.isLogin = isLogin;
// 应该改成 await next() 确保异步接口也能正常执行
next();
}
}
也已设置允许跨域, 正确配置中间件
config.cors = {
origin: '*', // 匹配规则 域名+端口 *则为全匹配
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
};
config.middleware = ['auth'];
config.auth = {
ignore: '*/authcallback'
}