我遇到了一个非常奇怪的问题,实现了axios拦截器来处理过期的令牌并刷新它。
设置
我将使用访问和刷新标记实现JWT身份验证。
当请求被发送到需要JWT身份验证的API路由时,请求拦截器在这里确保头部包含Authorization with Bearer令牌。响应拦截器检查是否需要新的访问令牌,发送一个请求以刷新它,最后用新的配置更新axios示例。
我按照Dave Gray的video编写了代码,但使用了TypeScript。
问题
在测试这段代码时,我将刷新令牌的生存期设置得很长,而将访问令牌的生存期设置为5秒。在它过期后,当向受保护的路由发出请求时,一切都按照计划进行-来自后端的日志包含两个成功完成的请求:(1)使用401响应发送到受保护路由,然后(2)发送刷新请求。
此时,我在浏览器控制台(Chrome和Safari)中看到了DOMException,它声明setRequestHeader
无法执行,因为源代码函数不是有效的头值。当然,它不是!代码如下。
代码
const axiosPrivate = axios.create({
baseURL: BASE_URL,
headers: { "Content-Type": "application/json" },
withCredentials: true,
});
interface IRequestConfig extends AxiosRequestConfig {
sent?: boolean;
}
const useAxiosPrivate = () => {
const { auth } = useAuth()!;
const refresh = useRefreshToken();
React.useEffect(() => {
const requestInterceptor = axiosPrivate.interceptors.request.use(
(config: AxiosRequestConfig) => {
config.headers = config.headers ?? {};
if (!config.headers["Authorization"]) {
config.headers["Authorization"] = `Bearer ${auth?.token}`;
}
return config;
},
async (error: AxiosError): Promise<AxiosError> => {
return Promise.reject(error);
}
);
const responseInterceptor = axiosPrivate.interceptors.response.use(
(response: AxiosResponse) => response,
async (error: AxiosError): Promise<AxiosError> => {
const prevRequestConfig = error.config as IRequestConfig;
if (error?.response?.status === 401 && !prevRequestConfig?.sent) {
const newAccessToken = await refresh();
prevRequestConfig.sent = true;
prevRequestConfig.headers = prevRequestConfig.headers!;
prevRequestConfig.headers[
"Authorization"
] = `Bearer ${newAccessToken}`;
return axiosPrivate(prevRequestConfig);
}
return Promise.reject(error);
}
);
return () => {
axiosPrivate.interceptors.request.eject(requestInterceptor);
axiosPrivate.interceptors.response.eject(responseInterceptor);
};
}, [auth, refresh]);
return axiosPrivate;
};
错误
DOMException: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'function (header, parser) {
header = normalizeHeader(header);
if (!header) return undefined;
const key = findKey(this, header);
if (key) {
const value = this[key];
if (!parser) {
return value;
}
if (parser === true) {
return parseTokens(value);
}
if (_utils_js__WEBPACK_IMPORTED_MODULE_0__["default"].isFunction(parser)) {
return parser.call(this, value, key);
}
if (_utils_js__WEBPACK_IMPORTED_MODULE_0__["default"].isRegExp(parser)) {
return parser.exec(value);
}
throw new TypeError('parser must be boolean|regexp|function');
}
}' is not a valid HTTP header field value.
研究
到目前为止,我在互联网上只找到了一个similar issue,它有一些其他的链接。One of them给了我一个提示,它可能是axios
如何读取给axios示例的配置的问题。
我不确定这个问题是否真的存在于axios中。我将非常感谢任何关于这个问题的有用想法!
2条答案
按热度按时间ztmd8pv51#
我遇到了同样的问题,我通过手动为
axiosPrivate
而不是axiosPrivate(prevRequestConfig)
赋值来解决这个问题。a8jjtwal2#
多亏了Vampire Lestat's solution,我才能修改Dave的教程代码: