Fetch的使用
Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch()
方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
这种功能以前是使用 XMLHttpRequest
实现的。Fetch 提供了一个更理想的替代方案,可以很容易地被其他技术使用,例如 Service Workers
。Fetch 还提供了专门的逻辑空间来定义其他与 HTTP 相关的概念,例如 CORS 和 HTTP 的扩展。
请注意,fetch
规范与 jQuery.ajax()
主要有三种方式的不同:
- 当接收到一个代表错误的 HTTP 状态码时,从
fetch()
返回的 Promise 不会被标记为 reject, 即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的ok
属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。 fetch()
不会接受跨域 cookies;你也不能使用fetch()
建立起跨域会话。其他网站的Set-Cookie
头部字段将会被无视。fetch
不会发送 cookies。除非你使用了credentials 的初始化选项。(自 2017 年 8 月 25 日以后,默认的 credentials 政策变更为same-origin
。Firefox 也在 61.0b13 版本中进行了修改)
一个基本的 fetch 请求设置起来很简单。看看下面的代码:
1 fetch('http://example.com/movies.json') 2 .then(function(response) { 3 return response.json(); 4 }) 5 .then(function(myJson) { 6 console.log(myJson); 7 });
这里我们通过网络获取一个 JSON 文件并将其打印到控制台。最简单的用法是只提供一个参数用来指明想 fetch()
到的资源路径,然后返回一个包含响应结果的promise(一个 Response
对象)。
当然它只是一个 HTTP 响应,而不是真的JSON。为了获取JSON的内容,我们需要使用 json()
方法(在 Body
mixin 中定义,被 Request
和 Response
对象实现)。
注意:Body mixin 还有其他相似的方法,用于获取其他类型的内容。参考 Body。
最好使用符合内容安全策略 (CSP)的链接而不是使用直接指向资源地址的方式来进行Fetch的请求。
支持的请求参数
fetch()
接受第二个可选参数,一个可以控制不同配置的 init
对象:
参考 fetch()
,查看所有可选的配置和更多描述。
1 // Example POST method implementation: 2 3 postData('http://example.com/answer', {answer: 42}) 4 .then(data => console.log(data)) // JSON from `response.json()` call 5 .catch(error => console.error(error)) 6 7 function postData(url, data) { 8 // Default options are marked with * 9 return fetch(url, { 10 body: JSON.stringify(data), // must match 'Content-Type' header 11 cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached 12 credentials: 'same-origin', // include, same-origin, *omit 13 headers: { 14 'user-agent': 'Mozilla/4.0 MDN Example', 15 'content-type': 'application/json' 16 }, 17 method: 'POST', // *GET, POST, PUT, DELETE, etc. 18 mode: 'cors', // no-cors, cors, *same-origin 19 redirect: 'follow', // manual, *follow, error 20 referrer: 'no-referrer', // *client, no-referrer 21 }) 22 .then(response => response.json()) // parses response to JSON 23 }
发送带凭据的请求
为了让浏览器发送包含凭据的请求(即使是跨域源),要将credentials: 'include'
添加到传递给 fetch()
方法的init
对象。
1 fetch('https://example.com', { 2 credentials: 'include' 3 })
如果你只想在请求URL与调用脚本位于同一起源处时发送凭据,请添加 credentials: 'same-origin'
。
1 // The calling script is on the origin 'https://example.com' 2 3 fetch('https://example.com', { 4 credentials: 'same-origin' 5 })
要改为确保浏览器不在请求中包含凭据,请使用 credentials: 'omit'
。
fetch('https://example.com', { credentials: 'omit' })
上传 JSON 数据
使用 fetch()
POST JSON数据
1 var url = 'https://example.com/profile'; 2 var data = {username: 'example'}; 3 4 fetch(url, { 5 method: 'POST', // or 'PUT' 6 body: JSON.stringify(data), // data can be `string` or {object}! 7 headers: new Headers({ 8 'Content-Type': 'application/json' 9 }) 10 }).then(res => res.json()) 11 .catch(error => console.error('Error:', error)) 12 .then(response => console.log('Success:', response));
上传文件
可以通过 HTML 元素,
FormData()
和 fetch()
上传文件。
1 var formData = new FormData(); 2 var fileField = document.querySelector("input[type='file']"); 3 4 formData.append('username', 'abc123'); 5 formData.append('avatar', fileField.files[0]); 6 7 fetch('https://example.com/profile/avatar', { 8 method: 'PUT', 9 body: formData 10 }) 11 .then(response => response.json()) 12 .catch(error => console.error('Error:', error)) 13 .then(response => console.log('Success:', response));
上传多个文件
可以通过HTML 元素,
FormData()
和 fetch()
上传文件。
1 var formData = new FormData(); 2 var photos = document.querySelector("input[type='file'][multiple]"); 3 4 formData.append('title', 'My Vegas Vacation'); 5 // formData 只接受文件、Blob 或字符串,不能直接传递数组,所以必须循环嵌入 6 for (let i = 0; i < photos.files.length; i++) { 7 formData.append('photo', photos.files[i]); 8 } 9 10 fetch('https://example.com/posts', { 11 method: 'POST', 12 body: formData 13 }) 14 .then(response => response.json()) 15 .then(response => console.log('Success:', JSON.stringify(response))) 16 .catch(error => console.error('Error:', error));
检测请求是否成功
如果遇到网络故障,fetch()
promise 将会 reject,带上一个 TypeError
对象。虽然这个情况经常是遇到了权限问题或类似问题——比如 404 不是一个网络故障。想要精确的判断 fetch()
是否成功,需要包含 promise resolved 的情况,此时再判断 Response.ok
是不是为 true。类似以下代码:
1 fetch('flowers.jpg').then(function(response) { 2 if(response.ok) { 3 return response.blob(); 4 } 5 throw new Error('Network response was not ok.'); 6 }).then(function(myBlob) { 7 var objectURL = URL.createObjectURL(myBlob); 8 myImage.src = objectURL; 9 }).catch(function(error) { 10 console.log('There has been a problem with your fetch operation: ', error.message); 11 });
自定义请求对象
除了传给 fetch()
一个资源的地址,你还可以通过使用 Request()
构造函数来创建一个 request 对象,然后再作为参数传给 fetch()
:
1 var myHeaders = new Headers(); 2 3 var myInit = { method: 'GET', 4 headers: myHeaders, 5 mode: 'cors', 6 cache: 'default' }; 7 8 var myRequest = new Request('flowers.jpg', myInit); 9 10 fetch(myRequest).then(function(response) { 11 return response.blob(); 12 }).then(function(myBlob) { 13 var objectURL = URL.createObjectURL(myBlob); 14 myImage.src = objectURL; 15 });
Request()
和 fetch()
接受同样的参数。你甚至可以传入一个已存在的 request 对象来创造一个拷贝:
1 var anotherRequest = new Request(myRequest,myInit);
这个很有用,因为 request 和 response bodies 只能被使用一次(译者注:这里的意思是因为设计成了 stream 的方式,所以它们只能被读取一次)。创建一个拷贝就可以再次使用 request/response 了,当然也可以使用不同的 init
参数。
注意:clone()
方法也可以用于创建一个拷贝。它和上述方法一样,如果 request 或 response 的 body 已经被读取过,那么将执行失败。区别在于, clone()
出的 body 被读取不会导致原 body 被标记为已读取。
引自:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch