首页 > 解决方案 > Axios:在单独的文件中使用 baseUrl 会导致在 axios 请求标头中设置身份验证令牌时出现问题

问题描述

我曾经在请求中编写 API Url,如下所示:

export const getAllAdmins2 = () => dispatch => {
  axios
    .get("http://baseUrl:3083/api/admin/getAllAdmins")
    .then(retrievedAdmins => {
      console.log("getAllAdmins2");
      console.log(retrievedAdmins);
      // this.setState({
      //   usersInformation: retrievedAdmins.data
      // });
    })
    .catch(error => console.log(error));
};

但是,这可以通过在单独的文件中设置 URL 来改进:

conf/api.js

import axios from "axios";

export default axios.create({
  baseURL: `http://baseUrl:3083`
});

所以我将 API 请求更改为:

import API from "../conf/api";

export const getAllAdmins = () => dispatch => {
  API.get("api/admin/getAllAdmins")
    .then(retrievedAdmins => {
      console.log("retrievedAdmins insideAPI.get(api/admin/getAllAdmin)");
      console.log(retrievedAdmins);
      // this.setState({
      //   usersInformation: retrievedAdmins.data
      // });
    })
    .catch(error => console.log(error));
};

但是,这导致了一个奇怪的问题:负责在每个请求中自动设置身份验证令牌的代码不再起作用。 在后端,令牌是未定义的:

 2020-02-28T17:49:41+0100 <notice> TokenServices.js:76 Object.HasValidToken Access Token:undefined

这是负责设置身份验证标头的代码:

应用程序.js

if (localStorage.jwtToken) {
  // Set auth token header auth
  setAuthToken(localStorage.jwtToken);

  // Decode token and get user info and expiration
  const decoded = jwt_decode(localStorage.jwtToken);
  // Set User and is Authenticated
  store.dispatch(setCurrentUser(decoded));
  // Now if you reload a page, if the user has already logged-in you will still have his info in he state

  // Check for expired token
  const currentTime = Date.now() / 1000;
  if (decoded.exp < currentTime) {
    // Logout User
    store.dispatch(logoutUser());
    // Redirect to login
    window.location.href = "/login";
  }
}

实用程序/setAuthToken.js

// What we will do here will prevent us from manually making sure of having the token inside each relevant request
// If we're logged-in, we can call this function and it will always attach that authorization header
// TODO: Need to make sure that the token is stored inside x-access-token
import axios from "axios";

const setAuthToken = token => {
  console.log("setAuthToken is called");
  if (token) {
    // Apply to every request
    axios.defaults.headers.common = {
      // Authorization: token,
      //TODO: Not sure about this
      "x-access-token": token
    };
    console.log("token is: ");
    console.log(token);
    console.log("axios.defaults.headers.common: ");
    console.log(axios.defaults.headers.common);
  } else {
    // Delete the Auth header
    axios.defaults.headers.common = {
      //Authorization: token,
      "x-access-token": token
    };
  }
};
export default setAuthToken;

这是 setAuthToken 的记录结果:

setAuthToken.js:7 setAuthToken is called
setAuthToken.js:15 token is: 
setAuthToken.js:16 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibm9tIjoiYXZlbXBhY2UiLCJlbWFpbCI6ImF2ZW1wYWNlQGF2ZW1wYWNlLmNvbSIsIm1vdF9kZV9wYXNzZSI6IlUyRnNkR1ZrWDEvRGdCN3JUUjB1YTJvc1BIcm1hRkswN3pjTGd5aSsxcE09IiwibGFzdF9sb2dpbiI6bnVsbCwicm9sZSI6InN1cGVyX3VzZXIiLCJjcmVhdGVkQXQiOiIyMDIwLTAyLTI4VDA5OjQwOjE4LjM3MFoiLCJ1cGRhdGVkQXQiOiIyMDIwLTAyLTI4VDA5OjQwOjE4LjM3MFoiLCJpYXQiOjE1ODI5MDg0NjAsImV4cCI6MTU4MjkxMjA2MH0.8Btk4f0Bdw-pM2qGEbk0s5V-u3jBugIHYDKH8aoDzW8
setAuthToken.js:17 axios.defaults.headers.common: 
setAuthToken.js:18 {x-access-token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwib…A2MH0.8Btk4f0Bdw-pM2qGEbk0s5V-u3jBugIHYDKH8aoDzW8"}

它似乎正在工作。但是,正如我所说,当我在后端使用getAllAdmins时,它使用axios url的新实现,令牌undefined后端。但是,当我使用直接实现axios url 的getAllAdmins2,代码在后端很受欢迎,并且一切正常。

标签: javascriptreactjsjwtaxiospassport.js

解决方案


您的问题可能是由于 axios 实例conf/api.js是在您设置令牌之前创建的,axios.defaults因此您的实例不会受到影响。即您的订单是:

  • 创建没有令牌的 axios 实例(在 api.js 的 include/comiple 上完成)
  • 加载令牌并设置默认值

由于您实际上有一个单例 axios 实例,因此您可以在加载令牌时设置它的默认值来代替全局默认值,即

前:

// This is setting the defaults used when creating instance and the global axios is used
axios.defaults.headers.common = {
...

后:

import API from "../conf/api";

...
// This will set the the defaults of your singleton instance
API.defaults.headers.common = {
...

以上应该可以解决您当前设置的问题,但另一种选择是返回使用全局axios(例如axios.get),而是将基本 URL 设置为默认值,即:

// During app init:
axios.defaults.baseURL = 'http://your.base.url';

推荐阅读