前言
ES6中新增了一种HTTP数据请求的方式,就是fetch,它和XMLHttpRequest有许多相似的功能,但是相比XMLHttpRequest,fetch被设计成更具可扩展性和高效性。江湖上一直流传着 “传统ajax已死,fetch永生”的说法,下面详细说下二者
详情
1.XMLHttpRequest 请求数据
var xhr = new XMLHttpRequest();
xhr.open('GET',url);
xhr.responseType = 'json';
xhr.onload = function() {
console.log(xhr.response);
};
xhr.onerror = function() {
console.log("Oops,error");
};
xhr.send();
2. fetch请求数据
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(e => console.log("Oops,error",e))
两段代码相比之下,fetch更为简洁,而且fetch请求属于promise结构,直接.then()方法处理回调数据,当出错时,会执行catch方法,而且promise避免了回调金字塔的问题。
3.fetch浏览器支持情况
目前谷歌浏览器对fetch的支持良好,具体支持情况如下图
当然,你也可以去这里查看can i use
4.fetch请求的四种方式
get请求
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(e => console.log("Oops,e))
如果需要传递参数,需要拼接在url。
后面这里的调用的第一个then函数里面,返回结果是一个可读流形式
如果请求的是json数据,需要调用response.json()(这里的response是传递的参数)将可读流解析为json数据,在下一个then方法中,就可以得到想要的json数据了
同理,如果请求的txt文本数据,则需要调用response.text()来解析...更多调用的解析方法如下
response.arrayBuffer() 读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为ArrayBuffer格式的promise对象 response.blob() 读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为Blob格式的promise对象 response.formData() 读取Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为FormData格式的promise对象 response.json() 读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为JSON格式的promise对象 response.text() 读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为USVString格式的promise对象
对于catch方法,只有报程序出错的时候才会执行。
post请求
fetch(url,{
method:'POST',headers:{
'Content-type':'application/json'// 设置请求头数据类型
},body:data
})
.then(res=>res.json())
.then(data=>console.log(data))
method:设置设置请求的方式,默认是get,另外还有PUT、DELETEheaders:设置请求头信息,当然,这里面还可以设置别的信息,比如:
var u = new URLSearchParams();
u.append('method','flickr.interestingness.getList');
u.append('api_key','<insert api key here>');
u.append('format','json');
u.append('nojsoncallback','1');
fetch(url,headers:u,body:data
})
.then(res=>res.json())
.then(data=>console.log(data))
另外,fetch可以在header中设置CORS跨域
u.append("Access-Control-Allow-Origin","*");
u.append("Access-Control-Allow-Headers","X-Requested-With");
u.append("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
u.append("X-Powered-By",' 3.2.1')
如果服务器不支持CORS,fetch提供了三种模式,其中no-cors可以继续访问服务器
fetch的mode配置项有3个值,如下:
-
same-origin:该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;其对应的response type为basic。 -
cors: 该模式支持跨域请求,顾名思义它是以CORS的形式跨域;当然该模式也可以同域请求不需要后端额外的CORS支持;其对应的response type为cors。 -
no-cors: 该模式用于跨域请求但是服务器不带CORS响应头,也就是服务端不支持CORS;这也是fetch的特殊跨域请求方式;其对应的response type为opaque。
针对跨域请求,cors模式是常见跨域请求实现,但是fetch自带的no-cors跨域请求模式则较为陌生,该模式有一个比较明显的特点:
该模式允许浏览器发送本次跨域请求,但是不能访问响应返回的内容,这也是其response type为opaque透明的原因,如下图:
呃,感觉这样虽然解决能跨域问题,但是请求不到任何数据,还是没有卵用...
注意: cors 支持 三种content-type 不支持 application/json
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
body:需要传递的参数
fetch请求默认是不会携带cookie信息,如果想要携带,需要在手动设置
fetch(url,{
method: 'POST',headers:{
'Content-type':'application/json'// 设置请求头数据类型
},credentials: "include"
})
credentials: "include" 设置请求头携带cookie信息
put请求
fetch(url,{
method:'PUT',body:data
})
.then(res=>res.json())
.then(data=>console.log(data))
delete请求
fetch(url,{
method:'DELETE',body:data
})
.then(res=>res.json())
.then(data=>console.log(data))
其实,post,put,delete,这三个请求代码上差不多,只是method中对应不同的请求方法不同而已。
如下是自己封装的fetch的API代码
HTML页面
<!DOCTYPE html> <html lang="en"> <head> <Meta charset="UTF-8"> <Meta name="viewport" content="width=device-width,initial-scale=1.0"> <Meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script src="easyhttp.js"></script> <script src="app.js"></script> </body> </html>
app.js
const url = 'http://jsonplaceholder.typicode.com/users';
let easyHttp = new EasyHttp;
// 请求数据
easyHttp.get(url)
.then(res=>console.log(res))
.catch(err=>console.log(err))
// 发送数据
const data = {
name:"Henry",username:"露丝",email:"lusi@qq.com"
};
// easyHttp.post(url,data)
// .then(res=>console.log(res))
// .catch(err=>console.log(err))
// 修改数据
// easyHttp.put(url+'/10',data)
// .then(res=>console.log(res))
// .catch(err=>console.log(err))
easyHttp.delete(url+'/2',data)
.then(res=>console.log(res))
.catch(err=>console.log(err))
easyhttp.js
/**
* fetch 增删改查 的API封装
*/
class EasyHttp{
// get 请求
get(url){
return new Promise((resolve,reject)=>{
fetch(url)
.then(res=>res.json())
.then(data=>resolve(data))
.catch(err=>reject(err))
})
}
// post 请求
post(url,data){
return new Promise((resolve,reject)=>{
fetch(url,{
method:'POST',headers:{
'Content-type':'application/json'// 设置请求头数据类型
},body:data
})
.then(res=>res.json())
.then(data=>resolve(data))
.then(err=>reject(err))
})
}
// put 请求修改数据
put(url,{
method:'PUT',body:data
})
.then(res=>res.json())
.then(data=>resolve(data))
.then(err=>reject(err))
})
}
// delete 删除数据
delete(url,{
method:'DELETE',body:data
})
.then(res=>res.json())
.then(data=>'删除数据成功。。。')
.then(err=>reject(err))
})
}
}
源码地址:戳一下
最后总结
fetch和XMLHttpRequest相比,主要有以下优点:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 同构方便,使用 isomorphic-fetch