一、网络请求的选择
-
传统的Ajax是基于XMLHttpRequest(XHR) -
jQuery-Ajax -
Fetch API- Fetch是AJAX的替换方案,基于Promise设计,很好的进行了
关注分离(发生数据和接收数据可以分开,不在一个地方),有很大一批人喜欢使用fetch进行项目开发; - 但是Fetch的缺点也很明显,首先需要明确的是Fetch是一个 low-level(底层)的API,没有帮助你封装好各种各样的功能 和实现;
- 比如发送网络请求需要自己来配置Header的Content-Type,不会默认携带cookie等;
- 比如错误处理相对麻烦(只有网络错误才会reject,HTTP状态码404或者500不会被标记为reject);
- 比如不支持取消一个请求,不能查看一个请求的进度等等;
- Fetch是AJAX的替换方案,基于Promise设计,很好的进行了
-
axios-
axios是目前前端使用非常广泛的网络请求库,包括Vue作者也是推荐在vue中使用axios;
-
主要特点包括:在浏览器中发送 XMLHttpRequests 请求、在 node.js 中发送 http请求、支持 Promise API、拦截请求和 响应、转换请求和响应数据等等;
-
axios的全称是 ajax i/o system
-
二、 基本使用
这里使用httpbin.org来进行测试
get
// 一般在这个生命周期函数中发送请求
componentDidMount() {
// 基本的get请求
axios({ // => axios可以直接作为函数进行使用
url: 'http://httpbin.org/get', // => 请求的地址
params: { // => 请求的参数,可以跟在地址的后边,但推荐直接写在这里
name: 'Klaus',
age: 23
},
method: 'get' // => 默认就是get请求,所以这个配置默认可以不写
}).then( res => console.log(res) ) // 表明axios返回的是一个Promise对象
}
// 参数1:url路径
// 参数2:query参数对象
const res = await axios.get('http://httpbin.org/get', {
name: 'Klaus',
age: 23
})
console.log(res)
post
axios({
url: 'http://httpbin.org/post',
data: {
name: 'Klaus',
age: 23
},
method: 'post'
}).then(console.log) // 成功的时候会将res返回,这里传递的函数,正好需要一个打印的参数
// 此时其就会将res传入console中并进行执行该函数
// 参数1:url
// 参数2: params参数对象
// 参数3:配置对象
const res = await axios.post('http://httpbin.org/post', {
name: 'Klaus',
age: 23
})
console.log(res)`
axios支持的请求
- axios(config)
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
axios的所有请求 本质上最后都会调用为axios.request方法
在axios的源码中
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context); // => 调用context.request,并接收到返回值
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance; //=> 返回结果,所以调用axios方法的本质就是在调用axios原型上的request方法
}
// Create the default instance to be exported
var axios = createInstance(defaults); // => 所以默认导出的axios是一个函数
// => 如果是delete,get,head,options方法,其会将传入的配置和method以及url进行合并作为配置进行传递
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url
}));
};
});
// => 如果是post,put,patch方法,那么传入的参数回合method,url,data进行合并
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: data
}));
};
});
//=> 所以 最后在axios中无论是哪一种支持的方法,其最后的本质都是在调用axios原型上的request方法
补充
axios.all
const request1 = axios.get('http://httpbin.org/get', {
name: 'Klaus',
age: 23
})
const request2 = axios.post('http://httpbin.org/post', {
name: 'Klaus',
age: 23
})
// 传入的多个请求的传入的参数格式为数组
axios.all([request1, request2]).then(console.log) //=> 输出的结果是以每一个请求的返回值组成的数组
// 所以如果需要直接获取传入的各个请求,可以使用数组的解构 [res1, res2] => console.log(res1, res2)
axios.all = function all(promises) {
return Promise.all(promises); // axios.all 的本质就是 调用了 Promise.all 函数(其参数也是多个请求组成的数组)
}
axios返回的数据不是单纯服务器返回的数据,而是基于服务器返回的数据基础上进行封装的数据
三、 配置信息
在实际开发过程中,可能会存在需要在请求的时候需要重复配置的信息,例如baseURL,header,timeout等
index.js
// 不要这么写,因为默认的axios.default中给多个配置项设置了默认值
// 如果这么写,就会将其指向一个新的对象,导致很多配置的默认选项不存在
// axios.defaults = {
// baseURL: 'http://httpbin.org',
// timeout: 5000
// }
// 需要单独修改属性
axios.defaults.baseURL = 'http://httpbin.org'
axios.defaults.timeout = 5000
// common 表示的是全部的请求方式
// axios.defaults.headers.common['token'] = 'asdsgfdsgfdg' // 所有的请求带上这个token
// axios.defaults.headers['token'] = 'asdadasdasf' // 这种写法和上面的写法是等价的
axios.defaults.headers.post['token'] = 'sdasdsarewr' // post请求的时候带上token,其余请求的时候不携带token0
App.js
const request1 = axios.get('/get', {
name: 'Klaus',
age: 23
})
四、 axios.create的基本使用
// 这就是所创建的一个新的axios对象
const _axios = axios.create({
baseURL: 'http://httpbin.org',
params: {
name: 'Klaus',
age: 23
}
})
const res = await _axios.get('/get', {
name: 'Klaus',
age: 23
})
console.log(res) // 此时就是使用新创建的axios实例来发生网络请求
适用场景: 全局的接口都是调用
http://www.wxf.com, 但是有一些接口需要请求http://www.klaus.com的时候,可以全局配置baseURL为
http://www.wxf.com,可以新建一个axios对象,里面传入特殊的配置,使用这个新建的axios对象来处理发往http://www.klaus.com的请求
新建的axios实例上,在传入配置项后,依旧可以使用defaults来修改新建的axios实例的配置项
此时请求内部的config配置 优先级 大于 defaults中配置 大于 创建实例时候create中传入的配置
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
//=> create的本质还是调用createInstance方法
五、 axios拦截器
请求拦截器:在发送请求时,请求被拦截;
-
发送网络请求时,在页面中添加一个loading组件作为动画;
-
某些网络请求要求用户必须登录,可以在请求中判断是否携带了token,没有携带token直接跳转到login页面;
-
对某些请求参数进行序列化;
响应拦截器:在响应结果中,结果被拦截;
- 响应拦截中可以对结果进行二次处理(比如服务器真正返回的数据其实是在response的data中);
- 对于错误信息进行判断,根据不同的状态进行不同的处理;
import axios from 'axios'
// 参数1:请求成功时候的callback callback参数: config 配置项信息对象
// 参数2:请求失败时候的callback callback参数: err 错误信息对象
axios.interceptors.request.use(config => {
console.log('请求被拦截了')
// 因为拦截,进行二次操作后,需要将其返回,以便于后续的操作可以获取到这个config
return config
})
// 参数1:请求成功时候的callback callback参数: res 响应体对象
// 参数2:请求失败时候的callback callback参数: err 错误信息对象
axios.interceptors.response.use(res => res.data, err => {
console.error(err)
// 如果外部需要使用到错误对象的话,最好进行导出
return err
})
补充
- 参数序列化
- 将参数由对象转换为字符串的过程叫做序列化
- 将参数由字符串转换为对象的过程叫做反序列化
- 可以借助
qs来进行操作