reactjs 'setRequestHeader'无法将源代码作为头值、axios和react执行

cuxqih21  于 2022-11-04  发布在  React
关注(0)|答案(2)|浏览(269)

我遇到了一个非常奇怪的问题,实现了axios拦截器来处理过期的令牌并刷新它。

设置

我将使用访问和刷新标记实现JWT身份验证。
当请求被发送到需要JWT身份验证的API路由时,请求拦截器在这里确保头部包含Authorization with Bearer令牌。响应拦截器检查是否需要新的访问令牌,发送一个请求以刷新它,最后用新的配置更新axios示例。
我按照Dave Gray的video编写了代码,但使用了TypeScript。
问题
在测试这段代码时,我将刷新令牌的生存期设置得很长,而将访问令牌的生存期设置为5秒。在它过期后,当向受保护的路由发出请求时,一切都按照计划进行-来自后端的日志包含两个成功完成的请求:(1)使用401响应发送到受保护路由,然后(2)发送刷新请求。
此时,我在浏览器控制台(Chrome和Safari)中看到了DOMException,它声明setRequestHeader无法执行,因为源代码函数不是有效的头值。当然,它不是!代码如下。

代码

  1. const axiosPrivate = axios.create({
  2. baseURL: BASE_URL,
  3. headers: { "Content-Type": "application/json" },
  4. withCredentials: true,
  5. });
  6. interface IRequestConfig extends AxiosRequestConfig {
  7. sent?: boolean;
  8. }
  9. const useAxiosPrivate = () => {
  10. const { auth } = useAuth()!;
  11. const refresh = useRefreshToken();
  12. React.useEffect(() => {
  13. const requestInterceptor = axiosPrivate.interceptors.request.use(
  14. (config: AxiosRequestConfig) => {
  15. config.headers = config.headers ?? {};
  16. if (!config.headers["Authorization"]) {
  17. config.headers["Authorization"] = `Bearer ${auth?.token}`;
  18. }
  19. return config;
  20. },
  21. async (error: AxiosError): Promise<AxiosError> => {
  22. return Promise.reject(error);
  23. }
  24. );
  25. const responseInterceptor = axiosPrivate.interceptors.response.use(
  26. (response: AxiosResponse) => response,
  27. async (error: AxiosError): Promise<AxiosError> => {
  28. const prevRequestConfig = error.config as IRequestConfig;
  29. if (error?.response?.status === 401 && !prevRequestConfig?.sent) {
  30. const newAccessToken = await refresh();
  31. prevRequestConfig.sent = true;
  32. prevRequestConfig.headers = prevRequestConfig.headers!;
  33. prevRequestConfig.headers[
  34. "Authorization"
  35. ] = `Bearer ${newAccessToken}`;
  36. return axiosPrivate(prevRequestConfig);
  37. }
  38. return Promise.reject(error);
  39. }
  40. );
  41. return () => {
  42. axiosPrivate.interceptors.request.eject(requestInterceptor);
  43. axiosPrivate.interceptors.response.eject(responseInterceptor);
  44. };
  45. }, [auth, refresh]);
  46. return axiosPrivate;
  47. };

错误

  1. DOMException: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'function (header, parser) {
  2. header = normalizeHeader(header);
  3. if (!header) return undefined;
  4. const key = findKey(this, header);
  5. if (key) {
  6. const value = this[key];
  7. if (!parser) {
  8. return value;
  9. }
  10. if (parser === true) {
  11. return parseTokens(value);
  12. }
  13. if (_utils_js__WEBPACK_IMPORTED_MODULE_0__["default"].isFunction(parser)) {
  14. return parser.call(this, value, key);
  15. }
  16. if (_utils_js__WEBPACK_IMPORTED_MODULE_0__["default"].isRegExp(parser)) {
  17. return parser.exec(value);
  18. }
  19. throw new TypeError('parser must be boolean|regexp|function');
  20. }
  21. }' is not a valid HTTP header field value.

研究
到目前为止,我在互联网上只找到了一个similar issue,它有一些其他的链接。One of them给了我一个提示,它可能是axios如何读取给axios示例的配置的问题。
我不确定这个问题是否真的存在于axios中。我将非常感谢任何关于这个问题的有用想法!

ztmd8pv5

ztmd8pv51#

我遇到了同样的问题,我通过手动为axiosPrivate而不是axiosPrivate(prevRequestConfig)赋值来解决这个问题。

  1. const responseIntercept = axiosPrivate.interceptors.response.use(
  2. response => response,
  3. async (error)=>{
  4. const prevRequest = error?.config;
  5. if (error?.response?.status === 403 && !prevRequest?.sent){
  6. const newAccessToken = await refresh();
  7. // console.log(prevRequest);
  8. return axiosPrivate({
  9. ...prevRequest,
  10. headers: {...prevRequest.headers, Authorization: `Bearer ${newAccessToken}`},
  11. sent: true
  12. });
  13. }
  14. return Promise.reject(error);
  15. }
  16. );
展开查看全部
a8jjtwal

a8jjtwal2#

多亏了Vampire Lestat's solution,我才能修改Dave的教程代码:

  1. const responseInterceptor = axiosPrivate.interceptors.response.use(
  2. (response: AxiosResponse) => {
  3. return response;
  4. },
  5. async (error: AxiosError): Promise<AxiosError> => {
  6. const prevRequestConfig = error.config as AxiosRequestConfig;
  7. if (error?.response?.status === 401 && !prevRequestConfig.sent) {
  8. prevRequestConfig.sent = true;
  9. const newAccessToken = await refresh();
  10. /* --- The modified line --- */
  11. prevRequestConfig.headers = { ...prevRequestConfig.headers };
  12. /* ------------------------- */
  13. prevRequestConfig.headers[
  14. "Authorization"
  15. ] = `Bearer ${newAccessToken}`;
  16. return axiosPrivate(prevRequestConfig);
  17. }
  18. return Promise.reject(error);
  19. }
  20. );
展开查看全部

相关问题