Lei Zhang

时光已逝永不回,
往事只能回味。
... ...
春风又吹红了花蕊,
你已经也添了新岁。

▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 96%



gvt salon 07 请求拦截

2018-09-14 » 没填完的坑 / Tutorial , Vuejs , 环境搭建

基础

  • 需要给所有 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 => {
				// 登录失败
				// 捕捉异常
			})
		}
	}
}
展开选填信息