使用 Fetch完成AJAX请求
写在前面
无论用JavaScript发送或获取信息,我们都会用到Ajax。Ajax不需要刷新页面就能发送和获取信息,能使网页实现异步更新。
几年前,初始化Ajax一般使用jQuery的ajax
方法:
$.ajax(‘some-url‘, { ?success: (data) => { /* do something with the data */ }, ?error: (err) => { /* do something when an error happens */}});
也可以不用jQuery,但不得不使用XMLHttpRequest
,然而这是[相当复杂]
幸亏,浏览器现在支持Fetch API,可以无须其他库就能实现Ajax
浏览器支持
fetch是相对较新的技术,当然就会存在浏览器兼容性的问题,当前各个浏览器低版本的情况下都是不被支持的,因此为了在所有主流浏览器中使用fetch 需要考虑 fetch 的 polyfill 了
require(‘es6-promise‘).polyfill();require(‘isomorphic-fetch‘);
引入这两个文件,就可以支持主流浏览器了
Fetch获取数据解读
使用Fetch获取数据很容易。只需要Fetch你想获取资源。
假设我们想通过GitHub获取一个仓库,我们可以像下面这样使用:
fetch(‘https://api.github.com/users/chriscoyier/repos‘);
Fetch会返回Promise,所以在获取资源后,可以使用.then
方法做你想做的。
fetch(‘https://api.github.com/users/chriscoyier/repos‘) ?.then(response => {/* do something */})
如果这是你第一次遇见Fetch,也许惊讶于Fetch返回的response
。如果console.log
返回的response
,会得到下列信息:
{ ?body: ReadableStream ?bodyUsed: false ?headers: Headers ?ok : true ?redirected : false ?status : 200 ?statusText : "OK" ?type : "cors" ?url : "http://some-website.com/some-url" ?__proto__ : Response}
可以看出Fetch返回的响应能告知请求的状态。从上面例子看出请求是成功的(ok
是true
,status
是200),但是我们想获取的仓库名却不在这里。
显然,我们从GitHub请求的资源都存储在body
中,作为一种可读的流。所以需要调用一个恰当方法将可读流转换为我们可以使用的数据。
Github返回的响应是JSON格式的,所以调用response.json
方法来转换数据。
还有其他方法来处理不同类型的响应。如果请求一个XML格式文件,则调用response.text
。如果请求图片,使用response.blob
方法。
所有这些方法(response.json
等等)返回另一个Promise,所以可以调用.then
方法处理我们转换后的数据。
fetch(‘https://api.github.com/users/chriscoyier/repos‘) ?.then(response => response.json()) ?.then(data => { ???// data就是我们请求的repos ???console.log(data) ?});
可以看出Fetch获取数据方法简短并且简单。
接下来,让我们看看如何使用Fetch发送数据。
Fetch发送数据解读
使用Fetch发送也很简单,只需要配置三个参数。
fetch(‘some-url‘, options);
第一个参数是设置请求方法(如post
、put
或del
),Fetch会自动设置方法为get
。
第二个参数是设置头部。因为一般使用JSON数据格式,所以设置ContentType
为application/json
。
第三个参数是设置包含JSON内容的主体。因为JSON内容是必须的,所以当设置主体时会调用JSON.stringify
。
实践中,post
请求会像下面这样:
let content = {some: ‘content‘};// The actual fetch requestfetch(‘some-url‘, { ?method: ‘post‘, ?headers: { ???‘Content-Type‘: ‘application/json‘ ?}, ?body: JSON.stringify(content)})// .then()...
API
fetch(url, { // url: 请求地址 ???method: "GET", // 请求的方法POST/GET等 ???headers: { // 请求头(可以是Headers对象,也可是JSON对象) ???????‘Content-Type‘: ‘application/json‘, ???????‘Accept‘: ‘application/json‘ ???}, ???body: , // 请求发送的数据 blob、BufferSource、FormData、URLSearchParams(get或head方法中不能包含body) ???cache: ‘default‘, // 是否缓存这个请求 ???credentials: ‘same-origin‘, //要不要携带 cookie 默认不携带 omit、same-origin 或者 include ???mode: "", ???/* ?????????mode,给请求定义一个模式确保请求有效 ???????same-origin:只在请求同域中资源时成功,其他请求将被拒绝(同源策略) ???????cors : 允许请求同域及返回CORS响应头的域中的资源,通常用作跨域请求来从第三方提供的API获取数据 ???????cors-with-forced-preflight:在发出实际请求前执行preflight检查 ???????no-cors : 目前不起作用(默认) ???*/}).then(resp => { ???/* ???????Response 实现了 Body, 可以使用 Body 的 属性和方法: ???????resp.type // 包含Response的类型 (例如, basic, cors). ???????resp.url // 包含Response的URL. ???????resp.status // 状态码 ???????resp.ok // 表示 Response 的成功还是失败 ???????resp.headers // 包含此Response所关联的 Headers 对象 可以使用 ???????resp.clone() // 创建一个Response对象的克隆 ???????resp.arrayBuffer() // 返回一个被解析为 ArrayBuffer 格式的promise对象 ???????resp.blob() // 返回一个被解析为 Blob 格式的promise对象 ???????resp.formData() // 返回一个被解析为 FormData 格式的promise对象 ???????resp.json() // 返回一个被解析为 Json 格式的promise对象 ???????resp.text() // 返回一个被解析为 Text 格式的promise对象 ???*/ ???if (resp.status === 200) return resp.json(); ???// 注: 这里的 resp.json() 返回值不是 js对象,通过 then 后才会得到 js 对象 ???throw New Error(‘false of json‘);}).then(json => { ???console.log(json);}).catch(error => { ???consolr.log(error);})
常用情况
1.请求 json
fetch(‘http://xxx/xxx.json‘).then(res => { ???????return res.json(); ???}).then(res => { ???????console.log(res); ???})
2. 请求文本
fetch(‘/xxx/page‘).then(res => { ???????return res.text(); ???}).then(res => { ???????console.log(res); ???})
3. 发送普通json数据
fetch(‘/xxx‘, { ???????method: ‘post‘, ???????body: JSON.stringify({ ???????????username: ‘‘, ???????????password: ‘‘ ???????}) ???});
4. 发送Form表单数据
var form = document.querySelector(‘form‘); ???fetch(‘/xxx‘, { ???????method: ‘post‘, ???????body: new FormData(form) ???});
5. 获取图片
fetch(‘/xxx‘).then(res => { ???????return res.blob(); ???}).then(res => { ???????document.querySelector(‘img‘).src = URL.createObjectURL(imageBlob); ???})
6. 上传文件
???var file = document.querySelector(‘.file‘) ???var data = new FormData() ???data.append(‘file‘, file.files[0]) ???fetch(‘/xxx‘, { ?????method: ‘POST‘, ?????body: data ???})
7. 封装
???require(‘es6-promise‘).polyfill(); ???require(‘isomorphic-fetch‘); ???export default function request(method, url, body) { ???????method = method.toUpperCase(); ???????if (method === ‘GET‘) { ???????????body = undefined; ???????} else { ???????????body = body && JSON.stringify(body); ???????} ???????return fetch(url, { ???????????method, ???????????headers: { ???????????????‘Content-Type‘: ‘application/json‘, ???????????????‘Accept‘: ‘application/json‘ ???????????}, ???????????body ???????}).then((res) => { ???????????if (res.status >= 200 && res.status < 300) { ???????????????return res; ???????????} else { ???????????????return Promise.reject(‘请求失败!‘); ???????????} ???????}) ???} ???export const get = path => request(‘GET‘, path); ???export const post = (path, body) => request(‘POST‘, path, body); ???export const put = (path, body) => request(‘PUT‘, path, body); ???export const del = (path, body) => request(‘DELETE‘, path, body);
参考
- Fetch API 初探
- Fetch API
- XHR or Fetch API ?
总结
Fetch是很好的方法,能发送和接收数据。不需要在编写XHR请求或依赖于jQuery。
尽管Fetch很好,但是其错误处理不是很直接。在处理之前,需要让错误信息进入到
catch
方法中。听说有个zlFetch库,改善了Fetch错误处理de问题。
But ! 现在有了Axios了,还跟我扯啥犊子呢!直接一步到位用Axios吧小盆友~
使用 Fetch完成AJAX请求
原文地址:https://www.cnblogs.com/wenqiangit/p/9918042.html