ajax技术
Ajax
是常用的一门与Web
服务器通信的技术,目前发送Ajax
请求的主要有4种方式:
- 原生XHR
- jquery中的$.ajax()
- axios
- fetch
原生的XHR
目前工作中已经很少去手写它了,前些年常用的是jquery
的ajax
请求,但是近些年前端发展很快,jquery
包装的ajax
已经失去了往日的光辉,取而代之的是新出现的axios
和fetch
,两者都开始抢占“请求”这个前端重要领域。目前只需要熟练使用Axios
就可以啦,Jquery
的ajax
会逐渐被时代淘汰,Fetch
虽然符合前端潮流,但是目前还尚不成熟,没有Axios
使用起来便利。
Jquery ajax
$.ajax({
type:"GET",
url:url,
data:data,
dataType:dataType
success:function(){},
error:function(){}
})
ajax
是jquery
对原生XHR
的封装,另外还增加了jsonp
的支持,让ajax
请求可以支持跨域请求,可以看这篇AJAX请求的五个步骤及步骤详解。
但是要注意的是:jsonp
请求本质不是XHR
异步请求,就是请求了一个js
文件,因此在浏览器的network
面板中的xhr
标签下看不到jsonp
的跨域请求,但是在js
标签下能看见。
- 缺点(慢慢被抛弃的原因):
- 要使用jquery ajax必须引入jquery整个大文件
- jquery ajax本身是针对MVC设计模式的编程,与当前流行的基于MVVM模式的vue、react等框架不符合
- jquery ajax本质是基于XHR的封装,而XHR本身架构不是很清晰,目前已采用fetch代替方案 总结
随着前端基于MVVM
模式的Vue
和React
新一代框架的兴起,以及ES6
等新规范的制定,像Jquery
这种大而全的JS
库注定是要走向低潮的。
Axios
什么是Axios?
Axios
是一个基于promise
的HTTP
库,它能够自动判断当前环境,自由切换在浏览器和node.js
环境中。如果是浏览器,就会基于XMLHttpRequests
实现;如果是node
环境,就会基于node
内置核心http
模块实现。同时,它还用promise
处理了响应结果,避免陷入回调地狱中去。
不仅如此,Axios
还可以拦截请求和响应、转化请求数据和响应数据、中断请求、自动转换JSON
数据、客户端支持防御XSRF
等。
axios({
method: 'post',
url: '/login',
data: {
username:'jackson',
password:'yyqx1128'
}
})
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
这种ajax
请求方式是Vue
框架的作者尤雨溪开始推荐使用的。其实Axios
的本质也是基于原生XHR
的封装,只不过它是基于ES6
的新语法Promise
的实现版本。并且具有以下几条特性:
- 从浏览器中创建XHR
- 从node.js中创建http请求
- 支持promise API
- 提供了并发请求的接口(重要,方便操作)
- 支持拦截请求和响应
- 支持取消请求
- 客户端支持防御CSRF攻击
手写Axios核心原理
1.基本使用
axios
基本使用方式主要有:
- axios(config)
- axios.method(url,data,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]])
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
username: 'jackson',
password:'yyqx1128'
}
});
// GET请求ID参数
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
2.实现axios
从axios(config)的使用上可以看出导出的axios是一个方法,从axios.get()的使用上可以看出导出的axios原型上会有get,post,put,delete等方法。
由分析可知,axios实际上是Axios类中的一个方法。我们可以先写一个request方法来实现主要的请求功能,这样就能使用axios(config)形式来调用了。
class Axios{
constructor(){
...
}
request(config){
return new Promise((resove)=> {
const {url='', data={}, method='get'} = config; //结构传参
const xhr = new XMLHttpRequest; // 创建请求对象
xhr.open(method, url, true);
xhr.onreadystatechange = () => {
if(xhr.readyState == 4 && xhr.status == 200) {
resove(xhr.responseText);
// 异步请求返回后将Promise转为成功态并将结果导出
}
}
xhr.send(data);
})
}
}
function CreateAxiosFn() {
let axios = new Axios;
let res = axios.request.bind(axios);
return req;
}
let axios = CreateAxiosFn();
然后搭建一个简易服务端代码,以测试请求的效果:
const express = require('express')
let app = express();
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', '*');
res.header('Content-Type', 'application/json;charset=utf-8');
next();
});
app.get('/getInfo', function(request, response){
let data = {
'username':'jackson',
'age':'20',
};
response.json(data);
});
app.listen(3000, function(){
console.log("服务器启动");
});
启动服务器后,在页面中测试请求是否成功:
<button onclick="getMsg()">点击</button>
<script src="./axios.js"></script>
<script>
function getMsg(){
axios({
method: 'get',
url: 'http://localhost:3000/getInfo'
}).then(res => {
console.log(res);
})
}
</script>
点击按钮后,可以看到请求成功并获取到数据。
总结
Axios除了和jquery ajax一样封装了原生的XHR,还提供了很多比如:并发请求、拦截等多种接口,同时它的体积还比较小,也没有下文fetch的各种问题,可以说是目前最佳的ajax请求方式了。
3.拦截器
在请求或响应被 then
或 catch
处理前拦截它们。
// -----------请求拦截--------
axios.intercepters.request.use(function(config) {
// 在发送请求之前
console.log('请求拦截:',config); // 对数据的处理
return config;
},function(error) {
return Promise.reject(error);
})
// -----------响应拦截--------
axios.intercepters.response.use(function(response) {
return response;
}, function(error) {
return Promise.reject(error);
})
axios.interceptors.response.use
和axios.interceptors.request.use
来定义请求和响应的拦截方法。
拦截器,顾名思义就是在请求之前和响应之前,对真正要执行的操作数据拦截住进行一些处理。那么如何实现呢,首先拦截器也是一个类,用于管理响应和请求。
class InterceptorsManage {
constructor(){
this.handlers = [];
}
use(onFulField, onRejected) {
// 将成功的回调和失败的回调都存放在队列中
this.handlers.push({
onFulField,
onRejected
})
}
}
这说明axios上有响应拦截器和请求拦截器,那么如何在axios上实现呢:
class Axios{
constructor(){
this.interceptors = {
request: new InterceptorsManage,
response: new InterceptorsManage
}
}
//....
}
在Axios的构造函数中新增interceptors
属性,然后定义request
和response
属性用于处理请求和响应。
执行use方法时,会把传入的回调函数放到handlers数组中。
Fetch
try{
var response=await fetch(url);
var data=response.json();
console.log(data);
}catch(e){
console.log('error is'+e);
}
上面说的$.ajax和Axios说到底本质都是对原生XHR的封装,但是Fetch可以说是新时代XHR的替代品。它的特性如下:
- 更加底层,提供更丰富的API
- 不基于XHR,是ES新规范的实现方式
但是目前Fetch还存在很多问题:
- fetch只对网络请求报错,对400,500都当做成功的请求
- fetch默认不会带cookie,需要添加配置项
- fetch没有办法原生监测请求的进度,而XHR可以
Fetch在使用上说实话目前还没有axios和jquery ajax方便,但“跨域的处理”Fetch做的性能要远比XHR要好。因为同源策略的约束,浏览器发送的请求是不能随便跨域的,一定要借助JSONP或者跨域头来协助跨域,而Fetch可以直接设置mode为“no-cors”来实现跨域访问,如下所示:
fetch('/login.json', {
method: 'post',
mode: 'cors',
data: {name:martin''}
}).then(function() { /* handle response */ });
我们会得到一个type为“opaque”(透明)的response。这个请求是真正抵达过后台的,但是浏览器不可以访问返回的内容,这也就是为什么response中的type为“opaque”(透明)的原因。
总结 Fetch还是一个新时代的半成品,很多地方并不完善,但是也有它的优势所在,总的来说,就是Fetch技术还需要时间的沉淀,目前还没有达到axios的性能。