在我的前端代码中,我有这段Axios
代码:
import axios from "axios";
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
const apiUrl = process.server ? `${process.env.FRONT}api/` : '/api/';
const api = axios.create({
baseURL: apiUrl,
headers: {
'Content-Type': 'application/json'
}
})
api.interceptors.request.use(function (config) {
const token = localStorage.getItem('token')
if (token) {
config.headers.common['Authorization'] = 'Bearer ' + token
}
return config;
}, function (error) {
return Promise.reject(error);
});
export const login = async (payload) => {
const { data } = await api.post(`login`, payload)
return data
}
这段代码的作用是设置一些带有令牌的头部信息。然后,该请求将转发到前端服务器:
router.post(`/login`, async (req, res) => {
try {
const data = await api.post('/login', req.body)
res.json(data.data)
} catch (e) {
res.status(e.response.status).json(e.response.data)
}
})
如果你在这里使用console.log(req.headers)
,一切都会没问题,头部信息看起来像这样:
req.headers {
accept: 'application/json, text/plain, */*',
'content-type': 'application/json',
host: 'localhost:8010',
connection: 'keep-alive',
'content-length': '898',
authorization: 'Bearer ...token...',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
...
}
以下是问题所在,当请求到后端时,它会被中间件auth
捕获:
router.post('/login', auth, accountController.login)
下面是这个中间件的样子:
import * as jwtService from './../services/jwtService';
import { Request, Response } from 'express';
import { CommonResponse } from "../responses/response";
export default async (req: Request, res: Response, next: any) => {
try {
if (req.headers.authorization) {
const user = await jwtService.getUser(req.headers.authorization.split(' ')[1])
if (user) next();
else return CommonResponse.common.unauthorized({ res })
} else {
return CommonResponse.common.unauthorized({ res })
}
} catch (e) {
return CommonResponse.common.unauthorized({res});
}
}
以下是问题所在,如果您在此处执行console.log(req.headers)
,您会看到:
{
accept: 'application/json, text/plain, */*',
'content-type': 'application/json',
'user-agent': 'axios/0.26.0',
'content-length': '898',
host: 'localhost:3000',
connection: 'close'
}
我的头信息怎么了?
顺便说一下,如果在前端服务器上执行以下操作:
const data = await api.post('/login', req.body, {headers: req.headers})
这样做是可行的,但是发生了什么?这就是拦截器应该工作的方式吗?
/login
路由。您有一个前端
,使用api.post
向您的第一个(前端)服务器发送请求。该请求使用router.post(..
进行监听,并使用api.post(
发送到后端服务器。我不理解这个前端服务器
,但我不认为它可以访问localStorage
。因此,在我看来,localStorage.get
将无法工作。因为localStorage
是浏览器方面的。如果我遗漏或误解了任何内容,请纠正我。 - archonlocalStorage
。如果在执行const { data } = await api.post(
login, payload)
之前,你执行了console.log(req.headers)
,你会看到这里有一个Bearer *token*
,但是这个前端头部信息并没有传递到后端服务器,这就是问题所在。 - dokichanconsole.log(req.headers)
会起作用,因为你正在记录req.headers
,而我试图告诉你的是,如果在Node上运行,window.localStorage.get
将不起作用,因为不应该有任何window
。因为localStorage
实际上在window
对象内部,我们不能在node
中使用它。这是特定于浏览器的。因此,您的前端代码可以访问localStorage
并且拦截器将正常工作,并且它将正确地将数据传递到服务器(req.headers),但是同样的拦截器在服务器上不起作用。 - archonconsole.log(req.headers)
是好的很正常,因为你是从客户端传递它的,客户端有运行在浏览器上的 HTML 网页,并且可以访问 localStorage ,所以它可以使用拦截器而没有任何问题并通过headers传递数据。但是如果你在frontend-server
上使用具有此特定拦截器的相同api
模块,它将失败。因为它不在浏览器上运行,它没有访问任何浏览器功能。 而localStorage.get
可能会引发错误。 - archon