模块的选择
Vue中发送网络请求有非常多的方式, 那么, 在开发中, 如何选择呢?
- 传统的Ajax是基于XMLHttpRequest(XHR)
- 使用jQuery-Ajax
- 官方在Vue1.x的时候, 推出了Vue-resource
- axios
比较差异: 传统的Ajax配置和调用方式等非常混乱.编码起来看起来就非常蛋疼.所以真实开发中很少直接使用, 而jQuery-Ajax,在Vue的整个开发中都是不需要使用jQuery了.为了方便我们进行一个网络请求, 特意引用一个jQuery,
你觉得合理吗?完全没有必要为了用网络请求就引用这个重量级的框架.Vue作者就在GitHub的Issues中说明了去掉vue-resource, 并且以后也不会再更新.那么意味着以后vue-reource不再支持新的版本时, 也不会再继续更新和维护.
对以后的项目开发和维护都存在很大的隐患.
综上,我们使用axios作为发送网络请求的模块
认识axios
基于promise用于浏览器和node.js的http客户端
功能特点:
- 支持浏览器和node.js
- 支持promise
- 能拦截请求和响应
- 能转换请求和响应数据
- 自动转换JSON数据
- 浏览器端支持防止CSRF(跨站请求伪造)
发送基本请求
HttpBin 介绍
httpbin
是一个HTTP Request & Response Service
,你可以向他发送请求,然后他会按照指定的规则将你的请求返回。这个类似于echo服务器
,但是功能又比它要更强大一些。 httpbin
支持HTTP/HTTPS,支持所有的HTTP动词,能模拟302跳转乃至302跳转的次数,还可以返回一个HTML文件或一个XML文件或一个图片文件(还支持指定返回图片的格式)。实在是请求调试中居家必备的良器!
httpbin怎么用
httpbin
的使用方法非常简单,你只需要把请求的地址修改为httpbin.org
即可。 比如:
1
| curl http://httpbin.org/user-agent
|
查看自己的GET请求
1
| curl http://httpbin.org/get
|
Get request
1 2 3 4 5 6 7 8 9
| #Get request //没有请求参数 axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
|
Post request
1 2 3 4 5 6 7 8 9 10 11 12
| #Post request //有请求参数 axios.post('/save', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
|
发送并发请求
有时候, 我们可能需求同时发送两个请求.使用axios.all, 可以放入多个请求的数组.axios.all([])
返回的结果是一个数组,使用axios.spread
可将数组 [res1,res2]
展开为 res1, res2
1 2 3 4 5 6 7 8 9 10 11 12 13
| function getUserAccount() { return axios.get('/user/12345'); }
function getUserPermissions() { return axios.get('/user/12345/permissions'); }
axios.all([getUserAccount(), getUserPermissions()]) .then(axios.spread((acct, perms)=>{ console.info(acct); console.info(perms); }));
|
可用的api别名
1 2 3 4 5 6 7 8 9
| axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.options(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) axios.patch(url[, data[, config]]) #注:当使用以上别名方法时,url,method和data等属性不用在config重复声明。
|
#全局配置
在上面的示例中, 我们的BaseURL
是固定的.事实上, 在开发中可能很多参数都是固定的.这个时候我们可以进行一些抽取, 也可以利用axiox
的全局配置
1 2 3 4 5 6 7 8 9 10 11 12
| //提取全局配置 axios.defaults.baseURL = ‘http://123.207.32.32:8000’ axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’;
//发送并发请求 axios.all([ axios.get('/user/12345'), axios.get('/user/12345/permissions')]) .then(axios.spread((acct, perms)=>{ console.info(acct); console.info(perms); }));
|
常见的配置选项
请求地址 |
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’, |
axios实例
为什么要创建axios
的实例呢?
当我们从axios
模块中导入对象时, 使用的实例是默认的实例.当给该实例设置一些默认配置时, 这些配置就被固定下来了.但是后续开发中, 某些配置可能会不太一样.比如某些请求需要使用特定的baseURL
或者timeout
或者content-Type
等.这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息.
拦截器
axios提供了拦截器,用于我们在发送每次请求或者得到相应后,进行对应的处理。
拦截器语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| axios.interceptors.request.use(function (response) { console.info("来到了request拦截的success中") return response; }, function (error) { console.info("来到了request拦截的error中") return error; });
axios.interceptors.response.use(function (response) { console.info("来到了response拦截的success中") return response.data; }, function (error) { console.info("来到了response拦截的error中") return error; });
|
拦截器中都做什么呢?
请求拦截可以做到的事情:
- 当发送网络请求时,在页面中添加一个loading组件,作为动画
- 某些请求要求用户必须登入,判断用户是否有token,如果没有token跳到login页面
- 对请求参数进行序列化
添加响应拦截器,统一处理服务器响应和异常
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 42
|
axios.interceptors.response.use( response => { return response }, error => {
const status = error.response.status const message = error.response.data.meta.message if (status === 401) {
if (message.indexOf('ERROR_CODE_001') > -1) { this.$message.error(errorCode.ERROR_CODE_001) }
window.location.href = `${window.location.origin}/login` return Promise.reject(error) }
if (status === 500) { if (message.indexOf('ERROR_CODE_003') > -1) { this.$message.error(errorCode.ERROR_CODE_003) return }
this.$message.error(message) }
return Promise.reject(error) } )
|
封装axios api http.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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
import axios from 'axios'
export default {
get (url, params) { return new Promise((resolve, reject) => { axios.get(url, { params: params }).then(res => { resolve(res.data) }).catch(err => { reject(err) }) }) },
post (url, params) { return new Promise((resolve, reject) => { axios.post(url, params) .then(res => { resolve(res.data) }) .catch(err => { reject(err) }) }) },
postFormData (url, params) { return new Promise((resolve, reject) => { axios({ headers: { 'Content-Type': 'multipart/form-data' }, transformRequest: [function (data) { const formData = new FormData() Object.keys(data).forEach(key => { formData.append(key, data[key]) }) return formData }], url, method: 'post', data: params }).then(res => { resolve(res.data) }).catch(err => { reject(err) }) }) } }
|