使用Express的JWT认证中间件无法从Axios GET请求的req中获取userId怎么办
问题根因
你遇到的问题是多个错误叠加导致的,逐一拆解如下:
- GET请求不支持携带请求体
HTTP规范中GET请求的请求体没有定义语义,绝大多数浏览器、HTTP客户端、服务端都会主动忽略GET请求携带的body内容。同时Axios的get方法参数规则和POST不同:axios.get(url[, 配置对象]),你传入的第二个参数formData会被Axios当成配置项处理,根本不会作为请求体发送。 - 请求头和传输数据格式完全不匹配
你创建了FormData对象(对应Content-Type为multipart/form-data),却手动把请求头的Content-Type设置成了application/json,就算是POST请求,服务端的express.json()中间件也完全无法解析对应内容。 - useCallback依赖错误
你当前的fetchPosts的依赖数组里包含了posts,而回调内部执行了setPosts,会导致posts更新后重新生成fetchPosts触发重复请求,陷入无限循环。
修复方案
方案1:保留GET请求(推荐,查询类接口符合REST规范)
GET请求的参数应该放在URL查询串中,不需要传递body,修改代码如下:
前端修改
const fetchPosts = useCallback(() => { Axios.get('http://localhost:3001/api/post', { // 将userId放到查询参数中,Axios会自动拼接到URL后 params: { userId: userId }, headers: { "Authorization": LStoken // 不需要手动设置Content-Type,GET请求无body无需该字段 } }) .then((response) => { console.log(response) setPosts(response.data) }) // 移除依赖数组中的posts,避免无限循环 }, [LStoken, userId])
中间件修改
将原来读取req.body.userId的逻辑改为读取req.query.userId:
const jwt = require('jsonwebtoken'); module.exports = (req, res, next) => { try { const token = req.headers.authorization.split(' ')[1]; const decodedToken = jwt.verify(token, 'RANDOM_TOKEN_SECRET'); const userId = decodedToken.userId; const moderator = decodedToken.moderator console.log(moderator) // 从query中读取userId console.log(req.query.userId) if (req.query.userId && req.query.userId !== userId || req.body.moderator == false ) { throw 'Invalid user ID'; } else { next(); } } catch { res.status(401).json({ error: new Error('Invalid request!') }); } };
方案2:改为POST请求(适合需要提交大量数据/文件的场景)
如果该接口需要提交其他数据(比如文件),可以改为POST请求,修改代码如下:
前端修改
const fetchPosts = useCallback(() => { // 不需要传文件的话完全没必要用FormData,直接传JSON对象即可 const postData = { userId: userId }; Axios.post('http://localhost:3001/api/post', postData, { headers: { "Authorization": LStoken // 不需要手动设置Content-Type,Axios会自动设为application/json } }) .then((response) => { console.log(response) setPosts(response.data) }) // 移除依赖数组中的posts,避免无限循环 }, [LStoken, userId])
后端路由修改
将原来的app.get('/api/post', ...)改为app.post('/api/post', ...)即可,原来的中间件逻辑不需要改动。
内容的提问来源于stack exchange,提问作者A.Tshi
相关产品推荐
相关产品推荐

