什么是Fetch
来源:互联网 发布:林弯弯的淘宝店外套 编辑:程序博客网 时间:2024/05/22 10:42
Fetch 是浏览器提供的原生 AJAX 接口。
由于原来的XMLHttpRequest不符合关注分离原则,且基于事件的模型在处理异步上已经没有现代的Promise等那么有优势。因此Fetch出现来解决这种问题。
Fetch API 提供了能够用于操作一部分 HTTP 的 JavaScript 接口,比如 requests 和 responses。它同时也提供了一个全局的 fetch() 方法——能够简单的异步的获取资源。
使用 window.fetch 函数可以代替以前的$. ajax、$.get 和 $.post。
Ajax与Fetch
JavaScript 通过XMLHttpRequest(XHR)来执行异步请求,这个方式已经存在了很长一段时间。虽说它很有用,但它不是最佳API。
它在设计上不符合职责分离原则,将输入、输出和用事件来跟踪的状态混杂在一个对象里。
而且,基于事件的模型与最近JavaScript流行的Promise以及基于生成器的异步编程模型不太搭(事件模型在处理异步上有点过时了)。
var xhttp = new XMLHttpRequest();xhttp.onreadystatechange = function() { if (this.readyState === 4 && this.status === 200) { console.log(this.responseText); }};xhttp.open("GET", "/", true);xhr.onload = function() { console.log(xhr.response);};xhr.onerror = function() { console.log("Oops, error");};xhttp.send();
而新的 Fetch API打算修正上面提到的那些缺陷。
Fetch API 提供了能够用于操作一部分 HTTP 的 JavaScript 接口,比如 requests 和 responses。它同时也提供了一个全局的 fetch() 方法——能够简单的异步的获取资源。
Fetch接口
Fetch 提供了对 Request 和 Response 等对象通用的定义。
发送请求或者获取资源,需要使用 fetch() 方法。
Headers
Fetch API 的Headers类允许你去对HTTP request和response headers执行各种操作。 这些操作包括:检索, 设置, 添加和删除。
一个Headers类里包含一个header列表, 它的初始值为空或者是零个或多个键值对。
下面是一个示例:
// 创建一个空的 Headers 对象,注意是Headers,不是Headervar headers = new Headers();// 添加(append)请求头信息headers.append('Content-Type', 'text/plain');headers.append('X-My-Custom-Header', 'CustomValue');// 判断(has), 获取(get), 以及修改(set)请求头的值headers.has('Content-Type'); // trueheaders.get('Content-Type'); // "text/plain"headers.set('Content-Type', 'application/json');// 删除某条请求头信息(a header)headers.delete('X-My-Custom-Header');// 创建对象时设置初始化信息var headers = new Headers({ 'Content-Type': 'text/plain', 'X-My-Custom-Header': 'CustomValue'});
由于Headers可以在request请求中被发送或者在response请求中被接收,并且规定了哪些参数是可写的,Headers对象有一个特殊的guard属性。这个属性没有暴露给Web,但是它影响到哪些内容可以在Headers对象中被改变。
一般来说,需要创建一个 Request 对象来包装请求头:
var request = new Request('/some-url', { headers: new Headers({ 'Content-Type': 'text/plain' })});fetch(request).then(function() { /* handle response */ });
Request
Request 对象表示一次 fetch 调用的请求信息。
可以使用构造函数Request.Request()来创建一个新的Request对象。
var req = new Request("/index.html");console.log(req.method); // "GET"console.log(req.url); // "http://example.com/index.html"
你也可以将一个建好的Request对象传给构造函数,这样将复制出一个新的Request:
var copy = new Request(req);console.log(copy.method); // "GET"console.log(copy.url); // "http://example.com/index.html"
URL以外的其他属性的初始值能够通过第二个参数传给Request构造函数。这个参数是一个json:
var uploadReq = new Request("/uploadImage", { method: "POST", headers: { "Content-Type": "image/png", }, body: "image data"});
Request对象的mode属性用来决定是否允许跨域请求,以及哪些response属性可读。可选的mode属性值为same-origin,no-cors(默认)以及cors。
- same-origin:模式很简单,如果一个请求是跨域的,那么返回一个简单的error,这样确保所有的请求遵守同源策略。
- no-cors:允许来自CDN的脚本、其他域的图片和其他一些跨域资源,但是首先有个前提条件,就是请求的method只能是”HEAD”,”GET”或者”POST”。
- cors:我们通常用作跨域请求来从第三方提供的API获取数据。这个模式遵守CORS协议。只有有限的一些headers被暴露给Response对象,但是body是可读的。
Request对象的credentials枚举属性决定了cookies是否能跨域得到。
Response
Fetch API 的Response接口呈现了对一次请求的响应数据。
你可以使用Response.Response() 构造函数来创建一个Response对象,但一般更可能遇到的情况是,其他的API操作返回了一个Response对象,例如一个简单的 GlobalFetch.fetch()。因此Response实例通常在fetch()的回调中获得。
Response有一系列的属性:
- Response.type 只读:包含Response的类型 (例如, basic, cors).
- Response.url 只读:包含Response的URL.
- Response.useFinalURL:包含了一个布尔值来标示这是否是该Response的最终URL.
- Response.status 只读:包含Response的状态码 (例如, 200 成功).
- Response.ok 只读:包含了一个布尔值来标示该Response成功(状态码200-299) 还是失败.
- Response.statusText 只读:包含了与该Response状态码一致的状态信息 (例如, OK对应200).
- Response.headers 只读:包含此Response所关联的Headers 对象.
处理body
无论Request还是Response都可能带着body。我们可以对其中的body进行处理。
Request和Response都为他们的body提供了以下方法,这些方法都读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并且都返回一个Promise对象。
- arrayBuffer():返回一个被解析为ArrayBuffer格式的promise对象
- blob():返回一个被解析为Blob格式的promise对象
- formData():返回一个被解析为FormData格式的promise对象
- json():返回一个被解析为JSON格式的promise对象
text():返回一个被解析为USVString格式的promise对象
处理json响应
fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { // 转换为 JSON return response.json();}).then(function(j) { // 现在, `j` 是一个 JavaScript object console.log(j); });
- 处理基本的Text / HTML响应
fetch('/next/page').then(function(response){ return response.text();}).then(function(text){ // <!DOCTYPE .... console.log(text); })
- 处理Blob结果
如果你想通过 fetch 加载图像或者其他二进制数据, 则会略有不同:
fetch('flowers.jpg') .then(function(response) { return response.blob(); }) .then(function(imageBlob) { document.querySelector('img').src = URL.createObjectURL(imageBlob); });
- 另一种常用的调用是提交表单数据
fetch('/submit-json',{ method:'post', body:JSON.stringify({ email:document.getElementById('email').value, answer:document.getElementById('answer').value })})
另外,非常重要的一点要说明,那就是Request和Response的body只能被读取一次!它们有一个属性叫bodyUsed,读取一次之后设置为true,就不能再读取了。
var res = new Response("one time use");console.log(res.bodyUsed); // falseres.text().then(function(v) { console.log(res.bodyUsed); // true});console.log(res.bodyUsed); // trueres.text().catch(function(e) { console.log("Tried to read already consumed Response");});
但有时候,我们希望多次访问body,API提供了一个clone()方法。调用这个方法可以得到一个克隆对象。不过要记得,clone()必须要在读取之前调用,也就是先clone()再读取。
var image1 = document.querySelector('.img1');var image2 = document.querySelector('.img2');var myRequest = new Request('flowers.jpg');fetch(myRequest).then(function(response) { var response2 = response.clone(); response.blob().then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); image1.src = objectURL; }); response2.blob().then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); image2.src = objectURL; });});
fetch()
Fetch API 中的GlobalFetch 接口包含了GlobalFetch.fetch() 方法,它被用于发送请求获取资源。
// url (必须), options (可选)fetch('/some/url', { method: 'get'}).then(function(response) {}).catch(function(err) { // 出错了;等价于 then 的第二个参数,但这样更好用更直观 :(});
fetch API 也使用了 JavaScript Promises 来处理结果/回调:
// 链式处理,将异步变为类似单线程的写法: 高级用法.fetch('/some/url').then(function(response) { return //... 执行成功, 第1步...}).then(function(returnedValue) { // ... 执行成功, 第2步...}).catch(function(err) { // 中途任何地方出错...在此处理 :( });
Fetch用法
浏览器支持情况
Fetch 的支持目前还处于早期的阶段,不过正在取得良好的进展。它目前在 Firefox 39 以上,和 Chrome 42 以上都被支持了。
如果你现在就想使用它,还可以用 Fetch Polyfil,用于支持那些还未支持 Fetch 的浏览器。
功能检测
Fetch API 的支持情况,可以通过检测 Headers、Request、Response 或 fetch() 是否在 Window 或 Worker 域中。
if(self.fetch) { // run my fetch request here} else { // do something with XMLHttpRequest?}
发起fetch请求
var myImage = document.querySelector("img");fetch("flowers.jpg").then(function(response){ return response.blob();}).then(function(myBlob){ var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL;})
以上代码中,我们通过网络获取了一个图片,然后将它插入到一个 < img> 标签中。
这个最简单的用法中,fetch() 接受了一个参数——请求的地址——然后返回一个包含 response(一个 Response 对象)的 promise 对象。
当然它只是一个 HTTP 响应,而不是真的图片。为了获取图片的内容,我们需要使用 blob() 方法。
接着,从 Blob 中获取 objectURL,之后再插入到 img 中。
自定义请求参数
fetch()接收第二个可选参数,一个可以控制不同配置的init对象。
var myHeaders = new Hearders();vart myInit = { method:'get', headers:myHeaders, mode:'cors', cache:'default'};fetch('flowers,jpg',myInit).then(function(response){ return response.blob();}).then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL;});
检测请求是否成功
如果遇到网络故障,fetch() promise 将会 reject,带上一个 TypeError 对象。
想要精确的判断 fetch() 是否成功,需要包含 promise resolved 的情况,此时再判断 Response.ok 是不是为 true。
fetch('flowers.jpg').then(function(response) { if(response.ok) { response.blob().then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; }); } else { console.log('Network response was not ok.'); }}).catch(function(error) { console.log('There has been a problem with your fetch operation: ' + error.message);});
自定义请求对象
除了传给 fetch() 一个资源的地址,你还可以通过使用 Request() 构造函数来创建一个 request 对象,然后再作为参数传给 fetch()
var myHeaders = new Headers();var myInit = { method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' };var myRequest = new Request('flowers.jpg',myInit);fetch(myRequest,myInit).then(function(response) { return response.blob();}).then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL;});
Request() 和 fetch() 接受同样的参数。你甚至可以传入一个已存在的 request 对象来创造一个拷贝:
var anotherRequest = new Request(myRequest,myInit);
这个很有用,因为 request 和 response bodies 只能被使用一次(因为设计成了 stream 的方式,所以它们只能被读取一次)。创建一个拷贝就可以再次使用 request/response 了。
实例
在我们自己的项目里,现在都是应用ajax的:
function ajaxNode(page){ $.get("nodeAdmin/ajaxNode", { page:page-1, },function(data){ $("#nodeList").html(data); }) }
试着更换成fetch:
function ajaxNode(page){ fetch("nodeAdmin/ajaxNode",{page:page-1}).then(function(response){ return response.text(); }).then(function(data){ $("#nodeList").html(data); }) }
it works!而且确实发现Promise这种链式操作非常清晰。
缺点
- 使用 fetch 无法取消一个请求。这是因为 Fetch API 基于 Promise,而 Promise 无法做到这一点。
由于 Fetch 是典型的异步场景,所以大部分遇到的问题不是 Fetch 的,其实是 Promise 的。
- 什么是Fetch
- FETCH
- Fetch
- FETCH
- Fetch
- fetch
- fetch
- fetch
- Fetch
- fetch
- Fetch()
- Fetch
- Fetch例子
- fetch.....into ..............
- 【转载】FETCH
- hibernate fetch
- Fetch next
- 关于fetch
- php使用gzip压缩传输js和css文件的方法
- 第十三周项目5-拓扑排序算法的验证
- android-学习-socketxxx
- 【Android】 修改系统的dialog样式
- Android-使用Timer实现5秒内接收到数据就进行打印,若超过5秒后没有收到数据再打印
- 什么是Fetch
- java覆盖与隐藏
- 用代码证明自己闲的蛋疼(三)——回溯法做数独
- C#中数组、ArrayList和List三者的区别
- 第十二周项目2 - 操作用邻接表存储的图
- maven+spring+springmvc+mybatis+ajax 框架下实现简单的聊天室
- 一套面试题
- Leetcode 10. Regular Expression Matching (Hard) (cpp)
- ConEmu设置当前目录打开右键菜单