vue-cli axios 项目有关于refresh_token、access_token过期失效刷新的处理

用户登录token失效处理方案
博客围绕用户登录后token处理展开。需求为登录返回access_token、refresh_token及20秒失效时间,根据用户交互情况处理token失效。前言指出网上常见方案不足,涉及axios二次封装和element - ui错误提示,思路在请求和响应拦截,最后给出代码。

需求

用户登录之后,返回access_token, refresh_token 还有返回失效时间20秒.
1,假如用户一直在数据交互。当access_token 失效了就用refresh_token 来更新一下 access_token.
2,假如用户登录之后啥也不干,那么access_token 失效了就跳到login页面.
3,假如用户在失效前30分钟存在数据交互,则用refresh_token 刷新 access_token。

前言

于在网上搜索了一大半。都是说的是在接口401状态去用refresh_token 去调取新 access_token,这样那还不是存在一直登录不退出的状态?不现实。。这里又涉及到axios的二次封装。刚好项目中用到element-ui, 索性把错误状态提示也做了一下。思路则是在请求拦截,响应拦截做文章。废话不多说。下面是代码。
源代码

代码

  import axios from 'axios';
  import Cookies from 'js-cookie';
  import { Message } from 'element-ui';
  import router from './../router/index';
  axios.defaults.timeout = 10000;

  var init = {                                              ❤️ 没画好?重画 [更多...]
    // 记录时间戳
    timer: null,
    // 是否调过refresh_token函数
    isRefresh: false,
    // 公用提示                                                  ???         ????
    openMessage: function(msg) {                             ????       ?????
      Message({                                            ?????     ?????
        message: msg,                                      ?????  ??????
        type: 'error',                                      ? ?????????
        showClose: true,                                     ? ??????????
      });                                                      ?????????
    },                                                           ???????
    getRefreshToken: function() {                                  ??????
      let params = {                                                 ?????、
        refresh_token: Cookies.get('refresh_token'),                   ????
      };                                                                 ???
      let that = this;                                                     ??
      axios({
        method: 'post',
        url: `api/v1/refresh_token${params}`,
      })
        .then(function(res) {
          if (res.data.access_token) {
            // 防止重复调refresh_token接口
            that.isRefresh = false;
            let result = res.data;
            let millisecond = new Date().getTime();
            let expiresTime = result.expires_in * 1000;
            let utilTime = millisecond + expiresTime;
            Cookies.set('access_token', result.access_token, { expires: expiresTime });
            Cookies.set('utilTime', utilTime);
            Cookies.set('refresh_token', result.refresh_token);
            Cookies.set('expires_in', result.expires_in);
          } else {
            //刷新token失败只能跳转到登录页重新登录
            localStorage.clear();
            Cookies.remove('access_token');
            Cookies.remove('utilTime');
            Cookies.remove('expires_in');
            Cookies.remove('refresh_token');
            router.replace({
              path: '/login',
              query: { redirect: router.currentRoute.fullPath },
            });
          }
        })
        .catch(function(err) {
          //刷新token失败只能跳转到登录页重新登录
          get_sys_logout();
          localStorage.clear();
          Cookies.remove('access_token');
          Cookies.remove('utilTime');
          Cookies.remove('expires_in');
          Cookies.remove('refresh_token');
          console.log(err);
          that.openMessage('登录失效');
          router.replace({
            path: '/login',
            query: { redirect: router.currentRoute.fullPath },
          });
        });
    },
  };

  //http request 拦截器
  axios.interceptors.request.use(
    config => {
      config.data = JSON.stringify(config.data);
      init.timer = new Date().getTime();
      if (Cookies.get('access_token')) {
        if ((parseInt(Cookies.get('utilTime')) - init.timer) / (1000 * 60 * 60) < 0) {
          Cookies.remove('access_token');
          Cookies.remove('utilTime');
          Cookies.remove('expires_in');
          Cookies.remove('refresh_token');
          get_sys_logout();
          localStorage.clear();
          router.replace({
            path: '/login',
            query: { redirect: router.currentRoute.fullPath },
          });
        }
        config.headers = {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${Cookies.get('access_token')}`,
        };
      } else {
        config.headers = {
          'Content-Type': 'application/json',
        };
      }
      return config;
    },
    error => {
      Message.error({
        message: '加载超时',
      });
      return Promise.reject(error);
    }
  );

  //响应拦截器即异常处理
  axios.interceptors.response.use(
    response => {
      if (Cookies.get('utilTime')) {
        if (!init.isRefresh) {
          // 是否是到期前30分钟
          if ((parseInt(Cookies.get('utilTime')) - init.timer) / (1000 * 60 * 60) < 0.5) {
            init.isRefresh = true;
            init.getRefreshToken();
          }
        }
      }
      return response;
    },
    err => {
      // debugger
      if (err && err.response) {
        switch (err.response.status) {
          case 400:
            console.log('错误请求');
            break;
          case 401:
            //刷新token失败只能跳转到登录页重新登录
            get_sys_logout();
            localStorage.clear();
            Cookies.remove('access_token');
            Cookies.remove('expires_in');
            Cookies.remove('utilTime');
            Cookies.remove('refresh_token');
            init.openMessage('登录失效');
            router.replace({
              path: '/login',
              query: { redirect: router.currentRoute.fullPath },
            });
            break;
          case 403:
            init.openMessage('拒绝访问');
            break;
          case 404:
            init.openMessage('请求错误,未找到该资源');
            break;
          case 405:
            init.openMessage('请求方法未允许');
            break;
          case 408:
            init.openMessage('请求超时');
            break;
          case 500:
            init.openMessage('服务器端出错');
            break;
          case 501:
            init.openMessage('网络未实现');
            break;
          case 502:
            init.openMessage('网络错误');
            break;
          case 503:
            init.openMessage('服务不可用');
            break;
          case 504:
            init.openMessage('网络超时');
            break;
          case 505:
            init.openMessage('http版本不支持该请求');
            break;
          default:
            init.openMessage(`连接错误${err.response.status}`);
        }
      } else {
        init.openMessage('连接服务器失败');
      }
      return Promise.resolve(err.response);
    }
  );
  export default axios;

<think>好的,我现在需要帮助用户在Vue2中使用Axios获取百度的access_token。首先,我得回忆一下百度API的相关流程。百度很多API需要access_token,通常是通过OAuth2.0的客户端凭证方式获取的。用户需要提供API Key和Secret Key,然后向指定的认证接口发送请求。 接下来,我需要确定用户是否已经注册了百度开发者账号,并创建了应用以获取这些密钥。但假设用户已经完成了这一步,现在的问题是如何在Vue2项目中用Axios实现这个请求。 首先,在Vue项目中安装Axios是必须的。通常使用npm或yarn来安装,所以在步骤里要提到这一点。然后,需要创建一个方法来发送POST请求到百度的token接口。百度获取access_token的接口地址是https://aip.baidubce.com/oauth/2.0/token,并且需要附带grant_type参数为client_credentials,以及client_id和client_secret。 在Vue2中,通常会在方法里调用Axios,可能需要处理跨域问题。但百度这个接口是否支持CORS呢?如果不支持,可能需要后端代理,不过根据经验,百度的一些接口是允许前端直接调用的。可能需要设置Axios的headers,比如Content-Type为application/x-www-form-urlencoded,因为OAuth2通常使用这种格式发送参数。 用户可能需要将参数作为查询字符串拼接在URL上,而不是放在请求体中,因为有些接口要求GET请求,但根据百度文档,获取access_token是POST请求,但参数是放在URL的查询参数中的。这一点需要仔细核对百度文档。例如,请求应该是POST,但参数以query string形式附加在URL后。 然后,处理响应,提取access_token,并处理可能的错误。例如,网络错误,或者API返回的错误码,如无效的API Key等。 另外,在Vue项目中,通常会把这类API请求封装成服务,比如放在src/services/auth.js中,然后在组件中调用。这样结构更清晰。同时,需要注意安全,不要将API密钥直接暴露在前端代码中,这样容易被他人获取。但如果是纯前端应用,可能没有其他办法,只能提示用户注意保密。 所以,总结步骤应该是: 1. 安装Axios。 2. 创建请求方法,使用Axios发送POST请求到指定URL,附带必要参数。 3. 处理响应和错误。 4. 封装到服务模块中,方便复用。 5. 注意安全,不要在代码中暴露密钥,或者建议通过后端来中转请求以保护密钥。 需要验证参数的传递方式是否正确,比如是否应该用params选项还是作为data发送。根据百度文档,可能需要将参数作为查询参数,即使使用POST方法。例如: POST /oauth/2.0/token?grant_type=client_credentials&client_id=YOUR_API_KEY&client_secret=YOUR_SECRET_KEY 这种情况下,Axios的请求配置应该是url加上查询参数,method是post,而data可能为空。或者,可能需要使用params配置,但POST请求的params会被拼接到URL上,而data是请求体。这时候需要确认百度接口接受哪种方式。查阅百度文档,发现获取access_token的请求参数是通过URL查询参数传递的,且使用POST方法。所以Axios的配置应该是: axios.post( &#39;https://aip.baidubce.com/oauth/2.0/token&#39;, null, { params: { grant_type: &#39;client_credentials&#39;, client_id: &#39;YOUR_API_KEY&#39;, client_secret: &#39;YOUR_SECRET_KEY&#39; } } ) 或者直接将参数拼接到URL中: axios.post(`https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${apiKey}&client_secret=${secretKey}`) 但更推荐使用params对象,这样Axios会自动处理URL的编码。 此外,处理响应时,可能需要将获取到的access_token存储到Vue的data中,或者Vuex store中,方便后续使用。同时需要考虑token过期时间,通常在响应中有expires_in字段,用户需要在一定时间后刷新token。 最后,编写代码示例时,确保替换掉实际的API Key和Secret Key,并提醒用户不要将密钥提交到版本控制系统中,可以使用环境变量来管理。</think>在Vue2中使用Axios获取百度API的`access_token`,需遵循以下步骤: --- ### 1. **安装Axios** 在项目中安装Axios依赖: ```bash npm install axios --save # 或 yarn add axios ``` --- ### 2. **创建请求方法** 在Vue组件或独立服务文件中,编写获取`access_token`的逻辑: ```javascript // 示例:在Vue组件中 import axios from &#39;axios&#39;; export default { data() { return { accessToken: &#39;&#39;, apiKey: &#39;YOUR_API_KEY&#39;, // 替换为你的API Key secretKey: &#39;YOUR_SECRET_KEY&#39; // 替换为你的Secret Key }; }, methods: { async getBaiduAccessToken() { const url = &#39;https://aip.baidubce.com/oauth/2.0/token&#39;; try { const response = await axios.post(url, null, { params: { grant_type: &#39;client_credentials&#39;, client_id: this.apiKey, client_secret: this.secretKey } }); // 提取access_token this.accessToken = response.data.access_token; console.log(&#39;access_token:&#39;, this.accessToken); } catch (error) { console.error(&#39;获取access_token失败:&#39;, error.response?.data || error.message); } } }, mounted() { this.getBaiduAccessToken(); // 组件加载时自动调用 } }; ``` --- ### 3. **关键参数说明** - **接口地址**: $$ \text{https://aip.baidubce.com/oauth/2.0/token} $$ - **必需参数**: - `grant_type`: 固定值`client_credentials` - `client_id`: 百度云控制台获取的API Key - `client_secret`: 百度云控制台获取的Secret Key --- ### 4. **安全建议** - **不要暴露密钥**:避免在前端代码硬编码敏感信息。可通过环境变量(如`.env`文件)管理: ```env VUE_APP_BAIDU_API_KEY=your_api_key VUE_APP_BAIDU_SECRET_KEY=your_secret_key ``` 代码中通过`process.env.VUE_APP_BAIDU_API_KEY`获取。 - **后端代理(推荐)**:更安全的做法是将密钥保存在后端服务器,前端调用后端接口间接获取`access_token`。 --- ### 5. **响应处理** 成功响应示例: ```json { "access_token": "24.xxx", "expires_in": 2592000, "session_key": "9mzdxxx", "scope": "public", "refresh_token": "25.xxx" } ``` - **access_token**: 用于后续API调用的凭证 - **expires_in**: 有效期(秒),需定期刷新 --- ### 6. **常见问题** - **跨域问题**:百度接口已支持CORS,通常无需额外配置。 - **参数错误**:检查`client_id`和`client_secret`是否正确。 - **网络错误**:使用`try/catch`捕获异常,增强鲁棒性。 --- 通过以上步骤,即可在Vue2中集成百度API的`access_token`获取功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值