背景

很多人在写前端代码的时候,都不做请求封装,这样容易出现的情况是,假设在一个项目中,有100个页面,每个页面都需要向服务器发送请求,来完成数据的交互,突然有一天,产品的哥们说,咱们得加个请求的验证,给请求交互的data里,加一个加密的数据,来保证数据的安全性,如果未进行封装的话,这100个页面中,每个请求都需要改一次,这就是个很庞大的工程,所以,我们在开始写代码的时候,对请求的封装,是一个很重要的设计

理解

所谓

操作

我们以Vue项目为例,使用vue-cli搭建项目,使axios来发送请求

文件结构如下

1
2
3
4
5
6
7
8
9
10
11
12
my-projext
|-node_modules
|-public
|-src
|-assets
|-components
|-router
|-store
|-views
|-App.vue
|-main.js
|-package.json

方法一:使用单独的文件来进行封装

首先,在src下新建一个文件夹api并新建一个api.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
my-projext
|-node_modules
|-public
|-src
+ |-api
+ |-api.js
|-assets
|-components
|-router
|-store
|-views
|-App.vue
|-main.js
|-package.json

api.js添加如下内容

1
2
3
4
5
6
7
8
9
10
const apiUrl = 'https://www.yoursite.com/api/';
const axios = require('axios');

export function request(options = {}) {
axios[options.methods](
apiUrl+options.url,
options.data
).then(options.success)
.catch(options.fail)
}

经过这样的封装后,在页面中使用,就变成了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
page中

import {request} from '@/api/api.js';
export default {
data(){
return {}
},
methdos:{
getData(){
request({
url:"getData",
data:{
param_1:'入参数据'
},
success:(res)=>{
console.log('成功回调')
}
})
}
}
}

也可以在main.js中进行统一引入,然后注入到Vue.prototype中,这样就不用单独页面进行单独引入了

1
2
3
4
5
6
7
8
9
//main.js
import {request} from '@/api/api.js';
Vue.prototype.$request = request;


//Page中使用
this.$request({
url:'xxxxxx'
})

这样的话,如果想在请求前增加请求拦截,只需要在公共方法中,增加一个拦截即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    const apiUrl = 'https://www.yoursite.com/api/';
const axios = require('axios');
+ const userData = require('@/api/userData.js');//引入放置用户信息的公共文件

export function request(options = {}) {
+ options=beforeRequest(options)
axios[options.methods](
apiUrl+options.url,
options.data
- ).then(options.success)
+ ).then((res)=>{
+ res=beforeResponse(res)
+ options.success&&options.success(res)
+ })
.catch(options.fail)
}

+ export function beforeRequest(options = {}) {//请求前拦截的地方
+ options.header = options.header||{}
+ options.header.token = userData.token;
+ return options
+ }

+ export function beforeResponse(res = {}) {//收到相应后拦截的地方
+ if(res.header.status==200){
+ if(res.data.resCode==0){
+ //业务成功逻辑
+ }else{
+ //业务失败逻辑
+ }
+ return res.data;//例如,只将回调中的data交给业务,而在拦截器里统一处理状态
+ }else{
+ alert("网络错误")
+ return res
+ }
+ }

方法二:Vuex中进行封装

我们将请求及请求拦截器,单独放置在vuex中的一个module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my-projext
|-node_modules
|-public
|-src
- |-api
- |-api.js
|-store
+ |- modules
+ |-api.js
|- index.js
|-assets
|-components
|-router
|-views
|-App.vue
|-main.js
|-package.json

api.js中的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const axios = require('axios');
export default {
state: {
apiUrl:'https://www.yoursite.com/api/'
},
mutations: {

},
actions: {
request({state,commit,dispatch},options={}){//请求方法
this.dispatch('beforeRequest',options).then((options)=>{
axios[options.methods](
apiUrl+options.url,
options.data
).then((res)=>{
return Promise.resolve(res)
}).catch(options.fail)
}).then((res)=>{
return this.dispatch('beforeRequest',options)
})
},
beforeRequest({state,commit,dispatch},options={}){//请求前拦截
options.header = options.header||{}
options.header.token = this.state.userData.token;
return Promise.resolve(options)
},
beforeResponse({state,commit,dispatch},res = {}) {//收到相应后拦截的地方
if(res.header.status==200){
if(res.data.resCode==0){
//业务成功逻辑
}else{
//业务失败逻辑
}
return Promise.resolve(res.data);//例如,只将回调中的data交给业务,而在拦截器里统一处理状态
}else{
alert("网络错误")
return Promise.reject(res)
}
}
}
}

Page中的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import {request} from '@/api/api.js';
export default {
data(){
return {}
},
methdos:{
getData(){
this.$store.dispatch('request',{
url:"getData",
data:{
param_1:'入参数据'
},
success:
}).then((res)=>{
console.log('成功回调')
}).catch(()=>{
console.log('失败回调')
})
}
}
}