前言
不推薦完全copy過去,可以看看我是如何針對我這邊業務; 做的一個axios的封裝及實現的思路
需求及實現
- 統一捕獲介面報錯
- 彈窗提示
- 報錯重定向
- 基礎鑑權
- 表單序列化
實現的功能
- 統一捕獲介面報錯 : 用的axios內建的攔截器
- 彈窗提示: 引入
Element UI
的Message
元件 - 報錯重定向: 路由鉤子
- 基礎鑑權: 服務端過期時間戳和token,還有藉助路由的鉤子
- 表單序列化: 我這邊直接用
qs
(npm模組),你有時間也可以自己寫
效果圖
坑都已經爬過,現在復現那些錯誤有點麻煩..所以沒法錄製動態圖
用法及封裝
- 用法
// 服務層 , import預設會找該目錄下index.js的檔案,這個可能有小夥伴不知道
// 可以去了解npm的引入和es6引入的理論概念
import axiosPlugin from "./server";
Vue.use(axiosPlugin);
複製程式碼
- 對axios的封裝(AXIOS:
index.js
)
import axios from "axios";
import qs from "qs";
import { Message } from "element-ui";
import router from "../router";
const Axios = axios.create({
baseURL: "/", // 因為我本地做了反向代理
timeout: 10000,
responseType: "json",
withCredentials: true, // 是否允許帶cookie這些
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
}
});
//POST傳參序列化(新增請求攔截器)
Axios.interceptors.request.use(
config => {
// 在傳送請求之前做某件事
if (
config.method === "post"
) {
// 序列化
config.data = qs.stringify(config.data);
// 溫馨提示,若是貴公司的提交能直接接受json 格式,可以不用 qs 來序列化的
}
// 若是有做鑑權token , 就給頭部帶上token
// 若是需要跨站點,存放到 cookie 會好一點,限制也沒那麼多,有些瀏覽環境限制了 localstorage 的使用
// 這裡localStorage一般是請求成功後我們自行寫入到本地的,因為你放在vuex重新整理就沒了
// 一些必要的資料寫入本地,優先從本地讀取
if (localStorage.token) {
config.headers.Authorization = localStorage.token;
}
return config;
},
error => {
// error 的回撥資訊,看貴公司的定義
Message({
// 餓了麼的訊息彈窗元件,類似toast
showClose: true,
message: error && error.data.error.message,
type: 'error'
});
return Promise.reject(error.data.error.message);
}
);
//返回狀態判斷(新增響應攔截器)
Axios.interceptors.response.use(
res => {
//對響應資料做些事
if (res.data && !res.data.success) {
Message({
// 餓了麼的訊息彈窗元件,類似toast
showClose: true,
message: res.data.error.message.message
? res.data.error.message.message
: res.data.error.message,
type: "error"
});
return Promise.reject(res.data.error.message);
}
return res;
},
error => {
// 使用者登入的時候會拿到一個基礎資訊,比如使用者名稱,token,過期時間戳
// 直接丟localStorage或者sessionStorage
if (!window.localStorage.getItem("loginUserBaseInfo")) {
// 若是介面訪問的時候沒有發現有鑑權的基礎資訊,直接返回登入頁
router.push({
path: "/login"
});
} else {
// 若是有基礎資訊的情況下,判斷時間戳和當前的時間,若是當前的時間大於伺服器過期的時間
// 乖乖的返回去登入頁重新登入
let lifeTime =
JSON.parse(window.localStorage.getItem("loginUserBaseInfo")).lifeTime *
1000;
let nowTime = new Date().getTime(); // 當前時間的時間戳
console.log(nowTime, lifeTime);
console.log(nowTime > lifeTime);
if (nowTime > lifeTime) {
Message({
showClose: true,
message: "登入狀態資訊過期,請重新登入",
type: "error"
});
router.push({
path: "/login"
});
} else {
// 下面是介面回撥的satus ,因為我做了一些錯誤頁面,所以都會指向對應的報錯頁面
if (error.response.status === 403) {
router.push({
path: "/error/403"
});
}
if (error.response.status === 500) {
router.push({
path: "/error/500"
});
}
if (error.response.status === 502) {
router.push({
path: "/error/502"
});
}
if (error.response.status === 404) {
router.push({
path: "/error/404"
});
}
}
}
// 返回 response 裡的錯誤資訊
let errorInfo = error.data.error ? error.data.error.message : error.data;
return Promise.reject(errorInfo);
}
);
// 對axios的例項重新封裝成一個plugin ,方便 Vue.use(xxxx)
export default {
install: function(Vue, Option) {
Object.defineProperty(Vue.prototype, "$http", { value: Axios });
}
};
複製程式碼
- 路由鉤子的調整(Router:
index.js
)
import Vue from "vue";
import Router from "vue-router";
import layout from "@/components/layout/layout";
// 版塊有點多,版塊獨立路由管理,裡面都是懶載入引入
import customerManage from "./customerManage"; // 客戶管理
import account from "./account"; //登入
import adManage from "./adManage"; // 廣告管理
import dataStat from "./dataStat"; // 資料統計
import logger from "./logger"; // 日誌
import manager from "./manager"; // 管理者
import putonManage from "./putonManage"; // 投放管理
import error from "./error"; // 服務端錯誤
import { Message } from "element-ui";
Vue.use(Router);
// 請跳過這一段,看下面的
const router = new Router({
hashbang: false,
mode: "history",
routes: [
{
path: "/",
redirect: "/adver",
component: layout,
children: [
...customerManage,
...adManage,
...dataStat,
...putonManage,
...manager,
...logger
]
},
...account,
...error
]
});
// 路由攔截
// 差點忘了說明,不是所有版塊都需要鑑權的
// 所以需要鑑權,我都會在路由meta新增新增一個欄位requireLogin,設定為true的時候
// 這貨就必須走鑑權,像登入頁這些不要,是可以直接訪問的!!!
router.beforeEach((to, from, next) => {
if (to.matched.some(res => res.meta.requireLogin)) {
// 判斷是否需要登入許可權
if (window.localStorage.getItem("loginUserBaseInfo")) {
// 判斷是否登入
let lifeTime =
JSON.parse(window.localStorage.getItem("loginUserBaseInfo")).lifeTime *
1000;
let nowTime = (new Date()).getTime(); // 當前時間的時間戳
if (nowTime < lifeTime) {
next();
} else {
Message({
showClose: true,
message: "登入狀態資訊過期,請重新登入",
type: "error"
});
next({
path: "/login"
});
}
} else {
// 沒登入則跳轉到登入介面
next({
path: "/login"
});
}
} else {
next();
}
});
export default router;
複製程式碼
axios可配置的一些選項,其他的具體看官網說明哈
export default {
// 請求地址
url: "/user",
// 請求型別
method: "get",
// 請根路徑
baseURL: "http://www.mt.com/api",
// 請求前的資料處理
transformRequest: [function(data) {}],
// 請求後的資料處理
transformResponse: [function(data) {}],
// 自定義的請求頭
headers: { "x-Requested-With": "XMLHttpRequest" },
// URL查詢物件
params: { id: 12 },
// 查詢物件序列化函式
paramsSerializer: function(params) {},
// request body
data: { key: "aa" },
// 超時設定s
timeout: 1000,
// 跨域是否帶Token
withCredentials: false,
// 自定義請求處理
adapter: function(resolve, reject, config) {},
// 身份驗證資訊
auth: { uname: "", pwd: "12" },
// 響應的資料格式 json / blob /document /arraybuffer / text / stream
responseType: "json",
// xsrf 設定
xsrfCookieName: "XSRF-TOKEN",
xsrfHeaderName: "X-XSRF-TOKEN",
// 下傳和下載進度回撥
onUploadProgress: function(progressEvent) {
Math.round(progressEvent.loaded * 100 / progressEvent.total);
},
onDownloadProgress: function(progressEvent) {},
// 最多轉發數,用於node.js
maxRedirects: 5,
// 最大響應資料大小
maxContentLength: 2000,
// 自定義錯誤狀態碼範圍
validateStatus: function(status) {
return status >= 200 && status < 300;
},
// 用於node.js
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 用於設定跨域請求代理
proxy: {
host: "127.0.0.1",
port: 8080,
auth: {
username: "aa",
password: "2123"
}
},
// 用於取消請求
cancelToken: new CancelToken(function(cancel) {})
};
複製程式碼
總結
我這個封裝雖說不是萬金油版本,但是我感覺大多用axios結合vue的小夥伴, 稍微改改都能直接拿來用~~~喲吼吼,喲吼吼..... 鑑權需要再嚴謹一些,token 可以遵循 JWT 的規格,以及引入中間層nodejs(對傳輸的做攔截封裝加解密,聚合介面);