引言
前端技术真是一个发展飞快的领域,在这个计算机快速发展的世界,网页的要求越来越高,前后端的桥梁应运而生,Jquery ajax, Axios, Fetch都来争一席之。总的来说,无论是哪一种,都是正对原生XHR的封装,加入相应的自己的特色而延伸出的一种新型的框架。
原生XHR的请求方式
原生XHR实现方式:
- 创建一个XMLHttpRequest的对象.
- 通过open与服务器建立连接 open(method,url,async) ,method包含 GET、POST、PUT方式。第三个参数同步(false)或者异步(true)
- 发送请求 **send(string) **,string(参数) 仅用于post请求,GET请求不需要传参数,如果有参数直接拼接到url中。
- 状态和响应,当readyState==4并且status==200时请求成功,否则请求失败.
get请求:
javascript
var xml=null;
if(XMLHttpRequest){
xml=new XMLHttpRequest; //兼容非IE6
}else{
xml=new ActiveXObject('Microsoft.XMLHTTP'); //兼容IE6浏览器
}
xml.open('GET',url,true);
xml.send();
xml.onreadystatechange=function(){
if(xml.readyState==4&&xml.status==200){
//请求成功
}else{
//请求失败
}
post请求:
javascript
var xml=null;
var data={a:1,b:2};
if(XMLHttpRequest){
xml=new XMLHttpRequest;
}else{
xml=new ActiveXObject('Microsoft.XMLHTTP')
}
xml.open('POST',url,true);
xml.send(data); //这里的data是要传递的参数
xml.onreadystatechange=function(){
if(xml.readyState==4&&xml.status==200){
//请求成功
}else{
//请求失败
}
}
JQuery请求方式
是对原生XHR的封装,除此以外还增添了对JSONP的支持。JQuery ajax经过版本的迭代,已经逼近完美,但是仍有很多不足.几个缺点:
- 本身是针对MVC的编程,不符合现在前端MVVM的浪潮
- 基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
- JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)
JQuery中ajax 实现:
get请求:
javascript
$.ajax({
type:"get",
url:"",
async:true,
timeout:3000, //timeout:响应超时时间,非必须参数
beforeSend:function(){
//这里是发送请求之前所要进行的操作
},
success:function(){
//请求成功
},
error:function(){
//请求失败
}
});
post请求:
javascript
$.ajax({
type:"post",
url:"",
data:{a:1,b:2},//需要传递的参数
async:true,
timeout:3000, //timeout:响应超时时间,非必须参数
beforeSend:function(){
//这里是发送请求之前所要进行的操作
},
success:function(){
//请求成功
},
error:function(){
//请求失败
}
});
Axios请求方式
只要提到axios,前段的人都会想到新兴起的一种框架,并且越来越火,那就是vue,vue的作者尤雨溪,不过vue3.0的全部改版,不知道会是什么样式?反正我很期待.言归正传,Axios本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,axios支持防止CSRF,是怎么做到的呢,就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。 从它的官网上可以看到它有以下几条特性:
- 从 node.js 创建 http 请求
- 支持 Promise API
- 客户端支持防止CSRF
- 提供了一些并发请求的接口(重要,方便了很多的操作)
安装axios:
- 方法一:npm install axios
- 方法二: CDN引入
JQuery中ajax 实现:
get请求:
javascript
//1.get请求(无参数)
axios.get('http://www.xxx')
.then(function(response){
//请求成功
}).catch(function(erroe){
//请求失败
});
//2.get请求(有参数)
axios.get('http://www.xxx?a=1&b=2')
.then(function(response){
//请求成功
}).catch(function(erroe){
//请求失败
});
post请求(必须引入qs对data进行stringify 安装axios时已经安装了qs,无需再安装,引入即可用。
):
javascript
// import Qs from 'qs'
let data=Qs.stringify({a:1,b:2});
axios.post('http://www.xxx',data)
.then(function(response){
//请求成功
}).catch(function(error){
//请求失败
})
//4.多个请求同时发送
function axiosOne(){
return axios.get('http://www.url.one')
};
function axiosTwo(){
return axios.get('http://www.url.two')
};
axios.all([axiosOne(),axiosTwo()])
.then(axios.spread(function(acct, perms){
console.log(acct);//请求一的结果;
console.log(perms);//请求二的结果
}))
Fetch
fetch号称是AJAX的替代品,它的好处在《传统 Ajax 已死,Fetch 永生》: 中提到有以下几点:
- 符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
- 更好更方便的写法,诸如:
javascript
try {
let response = await fetch(url);
let data = response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e);
}
PS:fetch我用的不是很多,更多资料请看, fetch的具体问题大家可以参考:《fetch没有你想象的那么美》《fetch使用的常见问题及解决方法》
我们对前后端交互有一定的了解,也对XHR进行了解,无论是axios,ajax,fetch,都是对XHR的进行一次的封装,之后新增自己的一些特色.其实的本质就是XHR,下面我们来了解下如何更好的使用XHR.
xhr.readyState(状态值)和xhr.status(状态码)的区别
- xhr.readyState,是指运行AJAX所经历过的几种状态,无论访问是否成功都将响应的步骤,可以理解成为xhr运行步骤,使用"xhr.readyState"获得态。
- xhr.status,是指无论AJAX访问是否成功,由HTTP协议根据所提交的信息,服务器所返回的HTTP头信息代码,使用"ajax.status"获得态。 总的来说,state代表一个整体的状态。而status是这个大的state下面具体的小的状态。
- 什么是readyState: readyState是XMLHttpRequest对象的一个属性,用来标识当前XMLHttpRequest对象处于什么状态。readyState总共有5个状态值,分别为0~4,每个值代表了不同的含义: a. 0:初始化,XMLHttpRequest对象还没有完成初始化 b. 1:载入,XMLHttpRequest对象开始发送请求 c. 2:载入完成,XMLHttpRequest对象的请求发送完成 d. 3:解析,XMLHttpRequest对象开始读取服务器的响应 e. 4:完成,XMLHttpRequest对象读取服务器响应结束
- 什么是status:status是XMLHttpRequest对象的一个属性,表示响应的HTTP状态码 在HTTP1.1协议下,HTTP状态码总共可分为5大类: 1xx:信息响应类,表示接收到请求并且继续处理 2xx:处理成功响应类,表示动作被成功接收、理解和接受 3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理 4xx:客户端错误,客户请求包含语法错误或者是不能正确执行 5xx:服务端错误,服务器不能正确执行一个正确的请求 100------客户必须继续发出请求 101------客户要求服务器根据请求转换HTTP协议版本 200------交易成功 201------提示知道新文件的URL 202------接受和处理、但处理未完成 203------返回信息不确定或不完整 204------请求收到,但返回信息为空 205------服务器完成了请求,用户代理必须复位当前已经浏览过的文件 206------服务器已经完成了部分用户的GET请求 300------请求的资源可在多处得到 301------删除请求数据 302------在其他地址发现了请求数据 303------建议客户访问其他URL或访问方式 304------客户端已经执行了GET,但文件未变化 305------请求的资源必须从服务器指定的地址得到 306------前一版本HTTP中使用的代码,现行版本中不再使用 307------申明请求的资源临时性删除 400------错误请求,如语法错误 401------请求授权失败 402------保留有效ChargeTo头响应 403------请求不允许 404------没有发现文件、查询或URl 405------用户在Request-Line字段定义的方法不允许 406------根据用户发送的Accept拖,请求资源不可访问 407------类似401,用户必须首先在代理服务器上得到授权 408------客户端没有在用户指定的饿时间内完成请求 409------对当前资源状态,请求不能完成 410------服务器上不再有此资源且无进一步的参考地址 411------服务器拒绝用户定义的Content-Length属性请求 412------一个或多个请求头字段在当前请求中错误 413------请求的资源大于服务器允许的大小 414------请求的资源URL长于服务器允许的长度 415------请求资源不支持请求项目格式 416------请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段 417------服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求 500------服务器产生内部错误 501------服务器不支持请求的函数 502------服务器暂时不可用,有时是为了防止发生系统过载 503------服务器过载或暂停维修 504------关口过��,服务器使用另一个关口或服务来响应用户,等待时间设定值较长 505------服务器不支持或拒绝支请求头中指定的HTTP版本
无论在封装还是在使用的过程中,有没有发现我们为什么要onreadystatechange的函数实现要同时判断readyState和status呢?下面我来说下为什么要同时使用. 如果我们只使用readyState
javascript
var getXmlHttpRequest = function () {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
}
else if (window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
}
};
var xhr = getXmlHttpRequest();
xhr.open("get", "1.txt", true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
alert(xhr.responseText);
}
};
由此可以看出,服务响应出错了,但还是返回了信息,这并不是我们想要的结果,如果返回不是200,而是404或者500,由于只使用readystate做判断,它不理会放回的结果是200、404还是500,只要响应成功返回了,就执行接下来的javascript代码,结果将造成各种不可预料的错误。所以只使用readyState判断是行不通的。
如果我们只使用status判断
javascript
var getXmlHttpRequest = function () {
try{
return new XMLHttpRequest();
}catch(e){
return new ActiveXObject("Microsoft.XMLHTTP");
}
};
var xhr = getXmlHttpRequest();
xhr.open("get", "1.txt", true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.status === 200) {
alert("readyState=" + xhr.readyState + xhr.responseText);
}
};
由此可以看出,结果却不像预期那样。响应码确实是返回了200,但是总共弹出了3次窗口!第一次是"readyState=2"的窗口,第二次是"readyState=3"的窗口,第三次是"readyState=4"的窗口。由此,可见onreadystatechange函数的执行不是只在readyState变为4的时候触发的,而是readyState(2、3、4)的每次变化都会触发,所以就出现了前面说的那种情况。可见,单独使用status判断也是行不通的。
所以我们在项目要封装XHR时候一定要注意,我们要同时readyState和status缺一不可。那么readyState和status的先后判断顺序会不会有影响呢?我们可以将status调到前面先判断,代码如 xhr.status === 200 && xhr.readyState === 4,但事实上,这对于最终的结果是没有影响的,但是中间的性能就不同了。由试验我们知道,readyState的每次变化都会触发onreadystatechange函数,假如先判断status,那么每次都会多判断一次status的状态。虽然性能上影响甚微,不过还是应该抱着追求极致代码的想法,把readyState的判断放在前面。