Node.js实现JWT获取不到请求头的Authorization,同源策略与预检请求
问题
今天在练习node.js实现JWT的时候,出现了一个怪问题:
下面是前端设置Authorization的代码:
request.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
config.headers.Authorization = `Bearer ${token}`
return config
},
error => {
return Promise.reject(error)
}
)
随后调了一个get /test的测试接口
后端测试代码:
const testRouter = require('./test')
router.use((req, res, next) => {
console.log('headers1:', req.headers)
res.set({
'Access-Control-Allow-Origin': 'http://localhost:3000',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
})
next()
})
router.use(testRouter)
这里处理了一下跨域,随后调用testRouter:
const express = require('express')
const router = express.Router()
const { verifyToken } = require('../utils/token')
router.use(verifyToken)
router.get('/test', async (req, res) => {
res.status(200)
res.send({ msg: 'test success', code: 2000, data: {} })
})
module.exports = router
这里调用了方法验证token,方法如下:
const verifyToken = async function (req, res, next) {
console.log(req.headers.authorization)
const token = req.headers.authorization.split(' ')[1]
jwt.verify(token, secretKey, function (err, decoded) {
if (err) {
console.log('verify error', err)
res.status(200)
return res.send({ code: 4004, msg: 'token无效' })
}
console.log('verify decoded', decoded)
next()
})
}
随后我写完代码开始测试,我发现 req.headers.authorization
怎么都打印不出来;
然后我在路由入口的中间件打印了一下req.header,我发现设置的Authorization根本不在header里,我就觉得很奇怪了,但是我又发现header打印了两次,诶,很怪,为什么会打印两次吖?
我突然想到,当前端使用axios发起请求时,浏览器检测到不是简单请求,就会发起一个预检请求,这样的话我后端的中间件首先会收到两次请求,而且因为没有特意去处理预检请求,所以预检请求会跟着中间件走下去,随后进入到token验证的方法里,预检请求当然没有设置的authorization,这样就会导致找不到authorization而报错。
解决方法
在路由入口的中间件下处理掉预检请求options,返回掉他。
router.options('*', (req, res) => {
res.status(200).send({ msg: '测试通过' })
})
简单与预检请求
不会触发 CORS 预检请求。这样的请求为 简单请求 。
- HTTP 方法限制:只能使用 GET、HEAD、POST 这三种 HTTP 方法之一。
- 自定义标头限制:请求的 HTTP 标头只能是以下几种常见的标头:
Accept
、Accept-Language
、Content-Language
、Last-Event-ID
、Content-Type
(仅限于application/x-www-form-urlencoded
、multipart/form-data
、text/plain
)。 - HTML 头部 header field 字段:DPR、Download、Save-Data、Viewport-Width、WIdth。
- 不使用自定义请求标头:请求不能包含用户自定义的标头。
- 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
其他的请求都是预检请求。
预检的请求要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,随后服务器返回允许跨域以及一系列的请求头信息到浏览器,接下来才能进行正常的请求响应。
转载自:https://juejin.cn/post/7370841518792458275