OPTIONS预检请求因缺自定义头被认证中间件拦截的解决方案
解决CORS预检OPTIONS请求导致的401认证问题
你的推测完全正确——问题出在浏览器自动发起的CORS预检OPTIONS请求不会携带自定义的x-access-token头,而你的认证中间件会对所有请求(包括OPTIONS)强制校验这个头,所以直接返回了401。
为什么OPTIONS请求不带自定义头?
根据CORS规范,预检请求(OPTIONS)的作用是向服务器确认:"我接下来要发一个带自定义头/credentials的请求,你允许吗?"。这个请求本身是浏览器自动生成的,只会携带CORS相关的基础头(比如Origin、Access-Control-Request-Headers),不会包含你手动添加的x-access-token这类自定义授权头。
正确的处理方式
你需要让认证中间件跳过对OPTIONS请求的校验,或者在CORS配置层直接处理OPTIONS请求,不让它进入后续的认证和代理流程。这里提供两种可行方案:
方案1:修改认证中间件,跳过OPTIONS请求
直接在认证中间件的开头加上判断,如果是OPTIONS请求,直接放行:
module.exports = (req, res, next) => { // 跳过OPTIONS预检请求的认证校验 if (req.method === 'OPTIONS') { return next(); } const token = req.headers['x-access-token'] console.log('token', token) if (token) { verifyToken(token, global.config.secret).then((verificationResponse) => { const { decoded, message } = verificationResponse if (!decoded) return res.status(401).json({ message }) req.decoded = decoded return next() }) .catch((err) => { console.error(err) res.status(500).json({ message: 'Internal error' }) }) } else return res.status(401).json({ message: 'Missing authentication token' }) }
方案2:在CORS配置中直接响应OPTIONS请求
如果你的CORS中间件是第一个被挂载的,可以直接在里面处理OPTIONS请求,返回200状态码,不需要进入后续中间件:
server.all('/*', (req, res, next) => { res.header('Access-Control-Allow-Origin', 'http://localhost:3000') res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, x-access-token') res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS') res.header('Access-Control-Allow-Credentials', 'true') // 直接响应OPTIONS预检请求,不进入后续流程 if (req.method === 'OPTIONS') { return res.sendStatus(200); } next() })
验证效果
修改后,浏览器发起的OPTIONS预检请求会被直接放行,不会触发认证校验;之后的实际GET请求会携带x-access-token头,正常经过认证中间件的校验,然后被代理到API服务器。
内容的提问来源于stack exchange,提问作者Kunok
相关产品推荐
相关产品推荐

