request.js 8.5 KB
Newer Older
sin's avatar
sin committed
1
import axios from 'axios'
2
import {baseUrl, dataSources} from './env';
sin's avatar
sin committed
3
import datas from '../data/data';
YunaiV's avatar
YunaiV committed
4
import { getAccessToken, getRefreshToken } from '../utils/cache.js';
5
import { Dialog } from 'vant';
YunaiV's avatar
YunaiV committed
6
import {setLoginToken} from "../utils/cache";
sin's avatar
sin committed
7

sin's avatar
sin committed
8 9 10 11 12
const serviceRouter = function(requestUrl) {
  function getConfig() {
    const configDev = {
      '/order-api': {
        prefix: '/order-api',
13
        target: 'http://127.0.0.1:18088/order-api',
sin's avatar
sin committed
14 15 16 17 18
      },
      '/user-api': {
        prefix: '/user-api',
        target: 'http://127.0.0.1:18082/user-api',
      },
sin's avatar
sin committed
19 20 21 22 23 24
      '/product-api': {
        prefix: '/product-api',
        target: 'http://127.0.0.1:18081/product-api',
      },
      '/promotion-api': {
        prefix: '/promotion-api',
25
        target: 'http://127.0.0.1:18085/promotion-api',
sin's avatar
sin committed
26
      },
27 28
      '/pay-api': {
        prefix: '/pay-api',
29
        target: 'http://127.0.0.1:18084/pay-api',
30
      },
31 32 33 34
      '/search-api': {
        prefix: '/search-api',
        target: 'http://127.0.0.1:18086/search-api',
      },
sin's avatar
sin committed
35 36 37 38 39
    };

    const configProd = {
      '/order-api': {
        prefix: '/order-api',
40
        target: 'http://api.shop.iocoder.cn:18088/order-api',
sin's avatar
sin committed
41 42 43
      },
      '/user-api': {
        prefix: '/user-api',
44
        target: 'http://api.shop.iocoder.cn:18099/user-api',
sin's avatar
sin committed
45
      },
sin's avatar
sin committed
46 47
      '/product-api': {
        prefix: '/product-api',
48
        target: 'http://api.shop.iocoder.cn:18099/product-api',
sin's avatar
sin committed
49 50 51
      },
      '/promotion-api': {
        prefix: '/promotion-api',
52 53 54 55
        target: 'http://api.shop.iocoder.cn:18099/promotion-api',
      },
      '/pay-api': {
        prefix: '/pay-api',
56
        target: 'http://api.shop.iocoder.cn:18099/pay-api',
sin's avatar
sin committed
57
      },
58 59 60 61
      '/search-api': {
        prefix: '/search-api',
        target: 'http://api.shop.iocoder.cn:18099/search-api',
      },
sin's avatar
sin committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    };

    if (process.env.NODE_ENV == 'development') {
      return configDev;
    } else {
      return configProd
    }
  }

  // function doCreateServer(config) {
  //   // 获取请求配置文件
  //   const createServer = {};
  //   for (const configKey in config) {
  //     const serverPrefix = configKey;
  //     const {target} = config[configKey];
  //     // 创建服务
  //     createServer[serverPrefix] = axios.create({
  //       baseURL: target, // api 的 base_url
  //       timeout: 5000, // request timeout
  //       headers: {
  //         'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  //       }
  //     });
  //   }
  // }
  const config = getConfig();
YunaiV's avatar
YunaiV committed
88 89

  // TODO 芋艿,临时加下。
sin's avatar
sin committed
90 91 92 93
  // const createServer = doCreateServer(config);
  const indexOf = requestUrl.indexOf("/", 1);
  const _urlPrefix = requestUrl.substring(0,  indexOf);
  if (!config[_urlPrefix]) {
sin's avatar
sin committed
94 95 96
    // throw new Error(`服务路由,未找到可用服务! ${requestUrl}`);
    console.error(`服务路由,未找到可用服务! ${requestUrl}`)
    return ''
sin's avatar
sin committed
97 98 99 100 101 102 103 104 105 106 107 108
  }
  // if (!createServer[_urlPrefix]) {
  //   throw new Error("服务路由,未找到可用服务!");
  // }

  // const { target } = config[_urlPrefix];
  // const requestServer = createServer[_urlPrefix];
  // const targetRequestUrl = _requestUrl.replace(_urlPrefix, target)
  // return createServer;
  return config[_urlPrefix];
};

109
const service = axios.create({
sin's avatar
sin committed
110
  // baseURL: baseUrl, // api 的 base_url
111
  timeout: 30000, // request timeout
112 113 114
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  }
sin's avatar
sin committed
115 116
});

117 118 119
const servicef = function (parameter) {
  // debugger;
  if (dataSources == 'local') {
sin's avatar
sin committed
120
    //定义回调函数和axios一致
121 122 123 124 125 126
    const promist = new Promise(function (resolve, reject) {
      var data = datas[parameter.url];
      if (typeof data == 'string') {
        data = JSON.parse(data);
      }
      resolve(data);
127
    });
sin's avatar
sin committed
128 129
    return promist;
  }
130 131 132 133 134 135 136 137 138
  // 设置 access token
  // debugger;
  // if (getAccessToken()) {
  //   parameter.headers = {
  //     ...parameter.headers,
  //     'Authorization': `Bearer ${getAccessToken()}`,
  //   };
  // }
  // debugger;
sin's avatar
sin committed
139

sin's avatar
sin committed
140
  return service(parameter);
141
};
sin's avatar
sin committed
142

143 144
service.interceptors.request.use(
  config => {
YunaiV's avatar
YunaiV committed
145 146
    // 记录下原始请求的地址
    config.originUrl = config.url;
147
    // Do something before request is sent
sin's avatar
sin committed
148 149 150 151 152
    //   if (store.getters.token) {
    //     // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
    //     config.headers['X-Token'] = getToken()
    //   }

sin's avatar
sin committed
153 154 155
    // 切换地址
    const { target, prefix } = serviceRouter(config.url)
    let url = config.url = config.url.replace(`${prefix}`, target);
156
    // TODO 芋艿,这些 url 不用增加认证 token 。可能这么写,有点脏,后面看看咋优化下。
157
    if (url.indexOf('user-api/users/passport/mobile/send_register_code') !== -1
YunaiV's avatar
YunaiV committed
158 159
      || url.indexOf('user-api/users/passport/mobile/register') !== -1
      || url.indexOf('user-api/users/passport/refresh_token') !== -1) {
160 161 162 163
      return config;
    }

    // debugger;
164 165 166
    if (getAccessToken()) {
      config.headers['Authorization'] = `Bearer ${getAccessToken()}`;
    }
167 168 169 170 171 172 173
    return config
  },
  error => {
    // Do something with request error
    console.log(error) // for debug
    Promise.reject(error)
  }
174
);
sin's avatar
sin committed
175

YunaiV's avatar
YunaiV committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
function refreshToken(lastResponse) {
  // TODO 芋艿,可能会存在多个异步 callback 的情况。
  let refreshToken = getRefreshToken();
  return servicef({
    url: '/user-api/users/passport/refresh_token',
    method: 'post',
    params: {
      refreshToken
    }
  }).then(data => {
    // 设置新的 accessToken
    setLoginToken(data.accessToken, data.refreshToken);
    // 重新发起请求
    let config = lastResponse.config;
    return servicef({
      url: config.originUrl,
      method: config.method,
      params: {
        ...config.params,
      }
    });
  });
}

200
// response interceptor
sin's avatar
sin committed
201
service.interceptors.response.use(
202 203 204 205 206 207 208 209 210 211
  //response => response,
  /**
   * 下面的注释为通过在response里,自定义code来标示请求状态
   * 当code返回如下情况则说明权限有问题,登出并返回到登录页
   * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
   * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
   */
  response => {
    // debugger;
    const res = response.data;
212 213 214
    const code = res.code;
    if (code !== 0) {

215 216 217 218 219 220 221 222 223 224 225 226 227 228
      // // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
      // if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
      //   // 请自行在引入 MessageBox
      //   // import { Message, MessageBox } from 'element-ui'
      //   MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
      //     confirmButtonText: '重新登录',
      //     cancelButtonText: '取消',
      //     type: 'warning'
      //   }).then(() => {
      //     store.dispatch('FedLogOut').then(() => {
      //       location.reload() // 为了重新实例化vue-router对象 避免bug
      //     })
      //   })
      // }
229 230 231

      // TODO token 过期
      // TODO 需要拿 refresh token 置换
YunaiV's avatar
YunaiV committed
232 233 234 235 236
      if (code === 1002001011 // 访问令牌不存在
          || code === 1002001013 // 访问令牌已失效
          || code === 1002001017 // 刷新令牌不存在
          || code === 1002001018 // 刷新令牌已过期
          || code === 1002001019) {  // 刷新令牌已失效
237 238 239 240 241 242 243 244 245 246 247
        Dialog.confirm({
          title: '系统提示',
          message: res.message,
          confirmButtonText: '重新登陆',
          beforeClose: function (action, done) {
            done();
            if (action === 'confirm') {
              // debugger;
              // this.$router.push({ path: '/login' })
              // TODO 跳转到登陆页.不是很优雅
              location.replace('/#login');
248
              location.reload();
249 250 251
            }
          }
        });
YunaiV's avatar
YunaiV committed
252
      } else if (code === 1002001012) { // 访问令牌已过期
YunaiV's avatar
YunaiV committed
253
        return refreshToken(response);
254 255 256 257 258 259
      } else {
        Dialog.alert({
          title: '系统提示',
          message: res.message,
        });
      }
260 261 262 263 264 265 266 267 268
      return Promise.reject('error')
    } else {
      // if (typeof response.data.Tag == 'string') {
      //   return JSON.parse(response.data.Tag);
      // } else {
      //   return response.data.Tag;
      // }
      // debugger;
      return res.data;
sin's avatar
sin committed
269
    }
270 271
  },
  error => {
272 273 274 275 276 277 278
    Dialog.alert({
      title: '系统提示',
      message: error,
    });
    console.error(`请求失败`, error);
    throw new Error(error);
    // return Promise.reject(error)
279
  }
280
);
281

sin's avatar
sin committed
282

sin's avatar
sin committed
283
export default servicef