不管是 PC端 还是 移动端,都必须使用 ajaxRequest.js
1. 先在 src 目录, 新建 utils/ajaxRequest.js 。
在 ajaxRequest.js 将 Axios 进行封装。
ajaxRequest.js :
// 对 Axios 的封装
// 1.配置全局 loading
// 2.在请求头里加入 JWT Token, Token 一定要加入到拦截器
// 3.拦截器,可以对响应的结果,统一进行处理
import axios from 'axios'
// 导入 store
import store from '../store/index'
// 将 JWT Token 从localStorage中取出来, 加入到请求头中
import { getLocal } from './local'
class AjaxRequest {
// 配置一些默认参数
// 每一次请求,都会走这个构造函数
constructor () {
// 请求的路径
this.baseURL =
process.env.NODE_ENV == 'production' ? '/' : 'http://localhost:3000'
this.timeout = 3000 // 超时时间,3S
this.method = 'GET' // 默认方法为 'GET'
this.queue = {} // 队列,配置全局 loading。存放每次的请求 url
}
// 默认的参数,和传进来的参数,进行合并
merge (options) {
return { ...options, baseURL: this.baseURL, timeout: this.timeout }
}
setInterceptor (instance, url) {
// 对请求进行拦截
// 对每一次请求,进行拦截
// 1.更改请求头,将 Token 加入到请求头
// 2.每次请求时,都会加一个loading 效果
instance.interceptors.request.use(
config => {
console.log(config)
// config.headers['X-Auth-Token'] = 'xxxx' // 在请求头中加入了 X-Auth-Token 属性
config.headers['X-Auth-Token'] = getLocal('auth_token') // 将 JWT Token 加入到请求头中
config.headers.Authorization = 'xxx'
// 当第一次请求,显示loading, 剩下的时候,就不显示了
// 当都请求完毕后,去隐藏loading
if (Object.keys(this.queue).length === 0) {
// 如果对象为空,则表明是第一次,那么显示 loading
// 在请求之前,显示loading
store.commit('showLoading')
}
this.queue[url] = url // 把请求的url存入 queue对象
return config
},
err => {
return Promise.reject(err)
}
)
// 对响应的数据,进行拦截
// 如果上一个promise返回了一个常量,会作为下一个promise的输入
instance.interceptors.response.use(
res => {
// 响应一次,就把 queue对象中的url,删掉一个
delete this.queue[url]
// 如果queue对象为空,则表明 url被删完了,则最后一次的请求结束了
// 那么就隐藏 loading
// 这样就能保证,loading只显示一次。 并且只隐藏一次。
// 最迟不超过3S。
if (Object.keys(this.queue).length === 0) {
// 在响应之前,隐藏loading
store.commit('hideLoading')
}
// 对响应的状态码,进行统一处理
if (res.status === 304) {
return Promise.reject(res.status)
}
// 对每一次请求的数据,进行拦截
return res.data
},
err => {
return Promise.reject(err)
}
)
}
request (options) {
// url, method
let instance = axios.create() // 通过axios库创建一个axios实例
this.setInterceptor(instance, options.url)
let config = this.merge(options)
// axios执行后返回的是一个promise
return instance(config) // 前面加return。 其他组件可以这样用:axios.request().then()
}
}
export default new AjaxRequest()
// 在其他组件使用:
// import axios from './utils/ajaxRequest.js'
// axios.request({
// url: '/user',
// method: 'post'
// }).then()
2. 在 utils 目录新建 local.js ,封装一些本地存储的方法
local.js:
// 本地存储
// 存入 localStorage
export const setLocal = (key, value) => {
if (typeof value === 'object') {
value = JSON.stringify(value)
}
localStorage.setItem(key, value)
}
// 取localStorage中的值
export const getLocal = key => {
return localStorage.getItem(key)
}
// 存入sessionStorage
export const setSession = (key, value) => {
if (typeof value === 'object') {
value = JSON.stringify(value)
}
sessionStorage.setItem(key, value)
}
// 取sessionStorage中的值
export const getSession = key => {
return sessionStorage.getItem(key)
}
3. 在 App.vue 页面里,加入 loading 的组件
使用的 UI框架是 vue ant design
App.vue:
<template>
<div id="app">
<!-- loading -->
<a-spin v-if="$store.state.isShowLoading">
<a-icon slot="indicator"
type="loading"
style="font-size: 48px"
spin />
</a-spin>
<router-view />
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/login">Login</router-link> |
<router-link to="/profile">Profile</router-link>
</div>
</div>
</template>
<style lang="less">
/* loading */
.ant-spin-spinning {
z-index: 1500;
position: fixed !important;
top: 50% !important;
}
</style>
4. 在 api/user.js 中使用 ajaxRequest.js
user.js:
// 用户登录接口
// 专门写,调取后端的接口
import axios from '../utils/ajaxRequest'
export const getUser = () => {
// return 以后,在其他组件,调用: getUser().then()
// import { getUser } from './api/user'
// getUser().then(data => {})
return axios.request({
url: '/user',
method: 'get'
})
}
// 登录方法
// 传入用户名和密码
export const login = (username, password) => {
return axios.request({
method: 'POST',
url: '/login',
data: {
username,
password
}
})
}
// 在main.js 中的beforeEach中,去校验用户是否登录
export const validate = () => {
return axios.request({
method: 'get',
url: '/validate'
})
}
5. 在 actions 中,调用 api/user.js 中的方法
store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import { login, validate } from '../api/user'
// import * as types from './mutation-types'
import { setLocal } from '../utils/local' // 将JWT Token 存入 localStorage
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isShowLoading: false, // 是否显示loading效果
username: 'x' // 登录后的用户名
},
mutations: {
showLoading (state) {
state.isShowLoading = true // 显示loading
},
hideLoading (state) {
state.isShowLoading = false // 隐藏loading
},
setUser (state, username) {
state.username = username // 更改公共状态
}
},
// 在actions中,去调取 api/user.js 中的方法
// 然后,在组件中,去触发 actions 中的方法
actions: {
// 一般在actions中,写接口调用
async doLogin ({ commit }, payload) {
console.log(payload.username)
console.log(payload.password)
// store.dispatch('doLogin')
let res = await login(payload.username, payload.password)
// 登录成功
if (res.code === 0) {
// 把用户名存入 Vuex
commit('setUser', res.username)
// 将返回客户端的JWT Token保存到客户端上,每次请求时,请求头上加上Token,
// 然后服务端校验 Token, 如果Token不正确,或者过期,则相当于没有登录
setLocal('auth_token', res.auth_token)
} else {
// 返回的失败的promise
return Promise.reject(res.data)
}
},
// 在 main.js 中的beforeEach 去校验用户是否登录
async doValidate ({ commit }) {
let res = await validate()
// 表示已登录过
if (res.code === 0) {
// 再给username设置一次值
commit('setUser', res.username)
// 再把校验后的Token,再存入客户端一次,从而延长时效。
setLocal('auth_token', res.auth_token)
}
return res.code === 0 // 返回用户是否已登录, true表示已登录, false表示用户失效
}
}
})
// 在组件中,调用
// store.dispatch('doLogin').then(data, err=> {
// console.log('xxxx')
// })
6. 关于使用 ajaxRequest.js 的注意点
在其他组件中使用:
// 在其他组件使用:
import axios from './utils/ajaxRequest.js'
axios.request({
url: '/user',
method: 'post'
}).then()