axiosブロッキングはhttpリクエストをカプセル化し、token再送リクエストをリフレッシュする

17188 ワード

プロジェクトの特定のニーズに応じてhttpリクエストを再カプセル化する場合があります.最近、会社でショッピングモールのプロジェクトをしています.私もvueシロなので、ネットで多くの資料を参考にして、需要を解決しました.私のプロジェクトを例にとると、ニーズは次のとおりです.
  • すべてのサーバに対する要求は先に'/GetMaintenanceState'インタフェースにアクセスし、サーバがメンテナンス中であれば要求をブロックし、メンテナンスページにジャンプしてメンテナンス情報を表示する.サーバが実行中の場合は、リクエストを再開します.
  • ログイン後に送信する要求:(ログイン時にインタフェース'Token'を要求し、access_tokenrefresh_tokenをlocalStorageに保存)で、リクエストのたびにカスタムリクエストヘッダAuthorizationを持参します.
  • access_tokenが期限切れになった後、refresh_tokenでtokenのリフレッシュを再要求し、refresh_tokenが期限切れになったらログインページにジャンプしてtokenを再取得します.
  • 私たちのすべてのインタフェースはネットワークの問題を除いて、返されるstatusは200(OK)、要求成功IsSuccesstrue、要求失敗IsSuccessfalseです.要求に失敗すると、応答のエラーコードErrorTypeCode10003-access_tokenは存在しないか、期限切れになり、10004-refresh_tokenは存在しないか、期限切れになります.

  • 構想
    2つのリクエストがあります.1つはTokenを必要とし、もう1つはTokenを必要としません.ここでは主に第1種について話します.
    requestとresponseブロッキングを設定します.サーバの圧力を軽減するために,要求を開始する際にサーバ状態を取得し,localStorageに格納し,10分以内に要求があれば状態を取得しない.requestブロッキングでサーバが実行されているか、access_tokenがあるかを検出し、ない場合はログインページにジャンプします.最も重要なのは、access_tokenが期限切れになった場合、responseブロッカーに設定する必要があるtoken再送要求をリフレッシュすることである.
    サーバがtokenを生成する過程で、2つの時間があります.1つはtoken失効時間(access_token失効時間)、1つはtokenリフレッシュ時間(refresh_token失効時間)です.refresh_tokenの有効期限はaccess_tokenの有効期限よりも長いに違いありません.access_tokenの有効期限が切れた場合、refresh_tokenでtokenをリフレッシュできます.
    カプセル化サーバのメンテナンスステータスを取得する関数
    import axios from 'axios';
    
    function getUrl(url) {
      if (url.indexOf(baseUrl) === 0) {
        return url;
      }
      url = url.replace(/^\//, '');
      url = baseUrl + '/' + url;
      return url;
    }
    function checkMaintenance() {
      let status = {};
      let url = getUrl('/GetMaintenanceState');
      return axios({
        url,
        method: 'get'
      })
        .then(res => {
          if (res.data.IsSuccess) {
            status = {
              IsRun: res.data.Value.IsRun, //        
              errMsg: res.data.Value.MaintenanceMsg //       
            };
            // localStorageSet        ,       ,     
            localStorageSet('maintenance', status);
            //        
            return Promise.resolve(status);
          }
        })
        .catch(() => {
          return Promise.reject();
        });
    }
    

    パッケージリフレッシュtokenの関数
    function getRefreshToken() {
      let url = getUrl('/Token');
      //        token   localStorage 
      let token = JSON.parse(localStorage.getItem('token'));
      return axios({
        url,
        method: 'post',
        data: 'grant_type=refresh_token&refresh_token=' + token.refresh_token,
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
          //      
          Authorization: 'Basic xxxxxxxxxxx'
        }
      })
        .then(res => {
          if (res.data.IsSuccess) {
            var token_temp = {
              access_token: res.data.access_token,
              refresh_token: res.data.refresh_token
            };
            localStorage.setItem('token', JSON.stringify(token_temp));
            //  access_token   session 
            sessionStorage.setItem('access_token', res.data.access_token);
            return Promise.resolve();
          } 
        })
        .catch(() => {
          return Promise.reject();
        });
    }
    

    ブロッキングの設定
    異なるニーズのリクエストをカプセル化するにはaxiosインスタンスを作成することが望ましい(ここでは主に最も複雑なリクエスト)
    requestブロッキング:
    import router from '../router';
    import { Message } from 'element-ui';
    
    const instance = axios.create();
    
    instance.interceptors.request.use(
      config => {
        //             ,localStorageGet  ,  10    false
        let maintenance = localStorageGet('maintenance');
        //         maintenance       10  ,    
        if (!maintenance) {
          return checkMaintenance()
            .then(res => {
              if (res.IsRun) {
              //   session  access_token
                let access_token = sessionStorage.getItem('access_token');
                //        ,        
                if (!access_token) {
                  router.push({
                    path: '/login',
                    query: { redirect: router.currentRoute.fullPath }
                  });
                  //       
                  return Promise.reject();
                } else {
                  config.headers.Authorization = `bearer ${access_token}`;
                }
                config.headers['Content-Type'] = 'application/json;charset=UTF-8';
                //            
                return config;
              } else {
                //          ,       ,      
                router.push({
                  path: '/maintenance',
                  query: { redirect: res.errMsg }
                });
                return Promise.reject();
              }
            })
            .catch(() => {
            //            
              return Promise.reject();
            });
        } else { //      maintenance
          if (maintenance.IsRun) {
            let access_token = sessionStorage.getItem('access_token');
            if (!access_token) {
              router.push({
                path: '/login',
                query: { redirect: router.currentRoute.fullPath }
              });
              return Promise.reject();
            } else {
              config.headers.Authorization = `bearer ${access_token}`;
            }
            config.headers['Content-Type'] = 'application/json;charset=UTF-8';
            return config;
          } else {
            router.push({
              path: '/maintenance',
              query: { redirect: maintenance.errMsg }
            });
            return Promise.reject();
          }
        }
      },
      err => {
        // err     ,        ,          
        return Promise.reject(err);
      }
    );
    

    responseブロッキング:
    これは私のこのプロジェクトの場合にのみ、すべてのリクエストが成功し、ErrorTypeコードで区別されているため、responseコールバックで処理されます.
    通常の場合、tokenが期限切れになってステータスコード401に戻り、errコールバック中に処理されるべきである.
    instance.interceptors.response.use(
      response => {
        // access_token      
        if (response.data.ErrorTypeCode === 10003) {
          return getRefreshToken()
            .then(() => {
              //     
              let access_token = sessionStorage.getItem('access_token');
              config.headers.Authorization = `bearer ${access_token}`;
              config.headers['Content-Type'] = 'application/json;charset=UTF-8';
              //     
              //        refresh_token   
              return instance(config).then(res => {
                if (res.data.ErrorTypeCode === 10004) {
                  router.push({
                    path: '/login',
                    query: { redirect: router.currentRoute.fullPath }
                  });
                  return Promise.reject();
                }
                //        data  
                return Promise.resolve(response.data);
              });
            })
            .catch(() => {
              // refreshtoken             
              router.push({
                path: '/login',
                query: { redirect: router.currentRoute.fullPath }
              });
              return Promise.reject();
            });
        }
        // refresh_token      
        if (response.data.ErrorTypeCode == 10004) {
          router.push({
            path: '/login',
            query: { redirect: router.currentRoute.fullPath }
          });
          return Promise.reject();
        }
        //        data  
        return response.data;
      },
      err => {
        return Promise.reject(err);
      }
    );
    

    パッケージング要求
    function request({ url, method, Value = null }) {
      url = getUrl(url);
      method = method.toLowerCase() || 'get';
      let obj = {
        method,
        url
      };
      if (Value !== null) {
        if (method === 'get') {
          obj.params = { Value };
        } else {
          obj.data = { Value };
        }
      }
      return instance(obj)
        .then(res => {
          return Promise.resolve(res);
        })
        .catch(() => {
          Message.error('    ,       ');
          return Promise.reject();
        });
    }
    //       
    export function get(setting) {
      setting.method = 'GET';
      return request(setting);
    }
    
    export function post(setting) {
      setting.method = 'POST';
      return request(setting);
    }
    

    使用
    import { post, get } from '@/common/network';
    
    post({
      url: '/api/xxxxx',
      Value: {
        GoodsName,
        GoodsTypeId
      }
    }).then(res => {
        //.....
    })
    

    以上のパッケージはこのプロジェクトのニーズに対応しているだけで、あなたに役に立つことを望んでいます.
    転載先:https://juejin.im/post/5d2689d2e51d457759648777