在前端开发时,离不开前后端数据交互,通过ajax后端接口取数据, Ajax
是常用的一门与Web
服务器通信的技术,目前发送Ajax
请求的主要有4种方式:
原生XHR
jquery中的$.ajax()
axios
fetch
原生XMLHttpRequest
代码实例
原生AJAX API
中核心提供的是一个 XMLHttpRequest
类型,所有的 AJAX
操作都需要使用到这个类型。
var request = new XMLHttpRequest(); // 创建XMLHttpRequest对象//ajax是异步的,设置回调函数request.onreadystatechange = function () { // 状态发生变化时,函数被回调 if (request.readyState === 4) { // 成功完成 // 判断响应状态码 if (request.status === 200) { // 成功,通过responseText拿到响应的文本: return success(request.responseText); } else { // 失败,根据响应码判断失败原因: return fail(request.status); } } else { // HTTP请求还在继续... }}// 发送请求:request.open('GET', '/api/categories');request.setRequestHeader("Content-Type", "application/json") //设置请求头request.send();//到这一步,请求才正式发出
使用原生的js
还是比较繁琐,实际工程中建议使用jQuery
之类的库,封装的ajax
请求方法非常好用,且解决了浏览器兼容性的问题。
Jquery ajax
代码示例
$.ajax({ type:"GET", url:url, data:data, dataType:dataType success:function(){}, error:function(){}})
以上代码,是Jquery
对原生XHR
的封装,另外还增加了jsonp
的支持,让ajax
请求可以支持跨域请求,x需要注意的是:jsonp
请求本质不是XHR
异步请求,只是请求了一个js
文件,因此在浏览器的network
面板中的xhr
标签下看不到jsonp
的跨域请求,但是在js
标签下能看见。
jsonp请求示例
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>使用jQuery-AJAX--读取获得跨域JSONP数据</title> <script src="./jquery-1.7.2.js" type="text/javascript"></script> <style type="text/css"> body,html{ font-family: "Microsoft Yahei"; } a{ text-decoration: none; } </style> </head> <body> <h2> <a href="javascript:void(0)" class="btnAJAX">点击AJAX获取数据JSONP跨域....</a> </h2> <script src="jquery.min.js"></script> <script type="text/javascript"> $(function() { $(".btnAJAX").click(function(){ $.ajax({ type : "get", async:false, url : "http://weather.123.duba.net/static/weather_info/101121301.html", dataType : "jsonp", // 服务端用于接收callback调用的function名的参数 jsonp: "", // callback的function名称 jsonpCallback:"weather_callback", success : function(json){ console.log(json); //浏览器调试的时候用 }, error:function(){ alert('fail'); } }); }); }); </script> </body></html>
效果如下:
当点击以上文字时,查看xhr
请求,发现并没有发出xhr
请求
再查看js
请求,发现js
发出了一个请求,因此jsonp
本质是js
请求而并非xhr
请求,只是$.ajax
把jsonp
请求封装到了ajax
里面而已。
其实jquery ajax
使用起来已经是很方便了,那为什么现在还会被慢慢抛弃呢?个人认为主要原因有以下几点:
要使用
jquery ajax
必须引入jquery
整个大文件,不是很划算;jquery ajax
本身是针对MVC
设计模式的编程,与当前流行的基于MVVM
模式的vue
、react
等框架不符合;jquery ajax
本质是基于XHR
的封装,而XHR
本身架构不是很清晰,目前已采用fetch
代替方案
总结
随着前端基于MVVM
模式的Vue
和React
新一代框架的兴起,以及ES6
等新规范的制定,像Jquery
这种大而全的JS
库注定是要走向低潮的。
Axios
代码示例
axios({ method: 'post', url: '/login', data: { username:'martin', password:'a1234567' }}).then(function (res) { console.log(res);}).catch(function (err) { console.log(err);});
axios
是一个基于Promise
用于浏览器和 nodejs
的 HTTP
客户端,本质上也是对原生XHR
的封装,只不过它是Promise
的实现版本,符合最新的ES
规范,有以下几条特性:
从浏览器中创建
XMLHttpRequests
从
node.js
中创建http请求支持
Promise API
支持转换请求数据和响应数据
支持拦截请求和响应
支持取消请求
自动转换
JSON
数据客户端支持防御
CSRF
攻击
总结
Axios
除了和Jquery ajax
一样封装了原生的XHR
,还提供了很多比如:并发请求、拦截等多种接口,同时它的体积还比较小,也没有下文fetch
的各种问题,可以说是目前最佳的ajax
请求方式了。
Fetch
代码示例
Fetch
的功能与 XMLHttpRequest
基本相同,但有三个主要的差异:
fetch()
使用Promise
,不使用回调函数,因此大大简化了写法,写起来更简洁;采用模块化设计,
API
分散在多个对象上(Response
对象、Request
对象、Headers
对象);通过数据流(
Stream
对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHTTPRequest
对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来。
用法:
fetch('url请求地址') .then(response => response.json()) .then(json => console.log(json)) .catch(err => console.log('Request Failed', err));
上面示例中,fetch()
接收到的response
是一个 Stream
对象,response.json()
是一个异步操作,取出所有内容,并将其转为 JSON
对象。Promise
可以使用 await
语法改写,使得语义更清晰。
async function getJSON() { try{ var response=await fetch(url); var data=response.json(); console.log(data); }catch(e){ console.log('error is'+e); }}
await
语句必须放在try...catch
里面,这样才能捕捉异步操作中可能发生的错误。
此外,需要注意一下几点:
1)只有网络错误,或者无法连接时,fetch()
才会报错,即使服务器返回的状态码是 4xx
或 5xx
,fetch()
也不会报错(即 Promise
不会变为 rejected
状态)。
要判断请求是否成功,一种方法是通过Response.status
属性,得到 HTTP
回应的真实状态码,才能判断请求是否成功,如下所示:
async function fetchText() { let response = await fetch(url); if (response.status >= 200 && response.status < 300) { return await response.text(); } else { throw new Error(response.statusText); }}
上面示例中,response.status
属性只有等于 2xx (200~299)
,才能认定请求成功。这里不用考虑网址跳转(状态码为 3xx
),因为fetch()
会将跳转的状态码自动转为 200。
另一种方法是判断response.ok是否为true。
if (response.ok) { // 请求成功} else { // 请求失败}
2)fetch
默认不会带cookie
,需要添加配置项(credentials
属性);
3)fetch
没有办法原生监测请求的进度,而XHR
可以。
Fetch
在使用上说实话目前还没有axios
和jquery ajax
方便,在工作中也是使用axios
的比较多。说到这里,你可能觉得Fetch
就是强行用ES
新规范做出来的代替XHR
的半成品,事实上我就是这么认为的。但是有一点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
是 XMLHttpRequest 的升级版,虽然部分功能不是十分完善,但是也有它的优势所在。浏览器原生提供该对象,当前浏览器基本都支持。基于promise对象,支持链式写法。
注意点:
1.fetch是有兼容问题的
IE系列是完全不支持的,主流浏览器的早起版本也不支持,所以如果在项目中使用需要做兼容方案处理。
2.fetch 不管请求处理成功还是失败,都会触发promise的resolve状态回掉。这个和传统的ajax 框架是有点区别的。fetch只有当网络故障导致请求发送失败或者跨域的时候才会触发reject的逻辑。我们可以通过response 对象的ok是否是true来判断是否是真正的成功。