基础
- 需要给所有 AJAX 请求添加统一的 Request Headers?
- 需要统计某个 API 请求的次数?
- 需要统一 HTTP Reqeust Method?
- 需要统一请求发送时的 Loading?
- 是的,你需要 HTTP INTERCEPTION
axios 简介
axios 也是对原生的 XMLHttpRequest 封装,它基于 Promise 实现,让并发请求、异步请求更加优雅
常用配置项
axios 拥有许多的请求参数配置项,常用的如下:
{ // 请求地址 url: '/user', // 请求方法 method: 'get', // 请求根路径 baseURL: 'http://example.com/api', // 自定义的请求头 headers:{'TOKEN':'TOKEN'}, // request body data: { key: 'value'}, // 超时设置 timeout: 1000 }
响应数据结构
{ // 服务端返回数据 data: {}, status: 200, statusText: "OK", headers: {}, config: {} }
常用方法
// GET 请求 axios.get() // POST 请求 axios.post() // PUT 请求 axios.put() // DELETE 请求 axios.delete() // 并发请求 axios .all([axios.get('product'), axios.post('/order')]) .then(axios.spread((res1, res2) => {}))
封装
由于现在需要对接 UMS 系统, 该服务端使用 JSON WEB TOKEN 来处理用户认证, 因此我们需要做好如下工作:
- 封装 base module, 根据 5-环境变量.md 配置好 UMS 及其他需要对接服务端的环境属性
- 封装 constant module, 定义一些常量, 例如: ums 登录连接
- 封装 auth module, 通过 localStorage 来管理 JWT
- 封装 http module, 返回 axios instance
touch ./src/constants/index.js touch ./src/utils/base.js touch ./src/utils/auth.js touch ./src/utils/http.js
// base.js export const eos_baseURL = process.env.NODE_ENV === "production" ? "http://prod.eos.gvt.com" : "http://localhost:8541" export const ums_baseURL = process.env.NODE_ENV === "production" ? "http://prod.ums.gvt.com" : "http://192.168.1.81:7001"
// constants/index.js import { ums_baseURL } from "../utils/base" export const GO_BACK_UMS = () => { window.location.href = `${ums_baseURL}/login_page_url` }
// auth.js // 建议不同项目设置不同的存储 key const StorageKey = "EOS_AUTHRIZATION_TOKEN" // 获取 jwt export function getToken() { return localStorage.getItem(StorageKey); } // 更新 jwt export function setToken(token) { return localStorage.setItem(StorageKey, token); } // 移除 jwt export function removeToken() { return localStorage.removeItem(StorageKey); }
// http.js // 1. 导入 axios 模块 import axios from "axios" // 2. 导入 base 模块 // eos_baseURL, 是 EOS 自身服务端的路径, 因此它将会成为 axios instance 的 baseURL // ums_baseURL, 不需要在此处导入, 我们只需要在调用 UMS 接口时, 覆盖 baseURL 即可 import eos_baseURL from "base" // 3. 导入 auth 模块 import { getToken, removeToken } from "auth" // 4. 导出 constants 模块 import { GO_BACK_UMS } from "../constants" // 5. 创建 axios 实例, 设置 baseURL 为 eos_baseURL // 从此刻起, 只要使用 HTTP 这个 axios 实例发送请求, 请求的根路径, 都会变成 eos_baseURL const HTTP = axios.create({ baseURL: eos_baseURL, timeout: 5000 }) // 6. 请求拦截 // 针对每一个请求, 我们需要获取 JWT, 若其存在, 则将其放入 request headers 中 HTTP.interceptors.request.use(config => { if (getToken()) { config.headers['Authorization'] = getToken() } return config }, error => { Promise.reject(error) }) // 7. 相应拦截 // 由于前后端分离, 现在用户登录是否过期, 前端必须自行处理. // 结合 UMS 相关错误码, 我们需要收到相应数据时,在出现指定过期错误码时, 将用户进行"注销" HTTP.interceptors.response.use(response => { let code = response.data.code if (code === "110002" || code === "110003" || code === "110103") { // 此处不一定需要 removeToken // localStorage 中 token 已过期, 后面的请求均会进入到该 if condition removeToken() GO_BACK_UMS() return } return response.data }, error => { return Promise.reject(error) }); // 8. 导出 HTTP 模块 export default HTTP
API
接下来, 我们来使用上一步封装好的 HTTP module, 进行 API 相关的封装
- 创建 api module
# UMS 登录等相关接口 touch ./src/api/user/index.js # EOS 管理员首页相关接口 touch ./src/api/admin/home.js
- 导入 HTTP module, 填充 HTTP axios instance
// user/index.js import HTTP from "../../utils/http" import { ums_baseURL } from "../../utils/base" // 接下来, 全部的 function 里的 HTTP(), 它都是 axios 的实例 // 因此在 HTTP() 中,我们只是覆盖或新增 axios request options // 当我们调用这些 function 时, axios 才会真正的发出请求 export function fetchToken(data = {}){ return HTTP({ baseURL: ums_baseURL, method: "post", url: "/ums/auth/login" data }) } export function fetchUser(){ return HTTP({ baseURL: ums_baseURL, method: "get", url: "/ums/auth/getUserRelateData" }) }
// admin/home.js // 由于 HTTP 现在默认即为 eos_baseURL // 因此我们无需导入它 // 也无需覆盖 HTTP.baseURL import HTTP from "../../utils/http" export function fetchHomeData(){ return HTTP({ method: "post", url: "/eos/admin/home" }) }
使用
封装好了 API module, 接下来我们将在视图组件中, 实现 API 调用及异常处理, 等等...
- 登录视图组件
import { fetchToken } from "api/user" export default { data(){ return { form: { username:"", password: "" } } }, methods: { login() { fetchToken(this.form) .then(response => { // 登录成功 }).catch(error => { // 登录失败 // 捕捉异常 }) } } }