Fetch API的fetch()请求是ajax的升级版?

前言

目前我们大多数用到的网络请求方式就是使用 XMLHttpRequest实现的。

fetch()是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。

fetch 规范与 jQuery.ajax() 主要有以下的不同:

  • 当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject,即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve(如果响应的 HTTP 状态码不在 200 - 299 的范围内,则设置 resolve 返回值的 ok 属性为 false),仅当网络故障时或请求被阻止时,才会标记为 reject。
  • fetch 不会发送跨域 cookie,除非你使用了 credentials 的初始化配置。
  • fetch()通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHTTPRequest 对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来。

基本用法

全局的 fetch() 方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。

如下:

Promise<Response> fetch(input[, init]);

第一个参数可以是一个字符串,包含要获取资源的 URL。一些浏览器会接受 blob:data: 作为 schemes.
也可以是一个 Request 对象。
第二个参数就是一个配置项对象,包括所有对请求的设置。可选的参数有:

  • method:请求使用的方法,如GET、POST等。
  • headers:请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
  • body:请求的 body 信息:可能是一个 BlobBufferSourceFormDataURLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
  • mode: 请求的模式,如 corsno-cors 或者 same-origin
  • credentials:请求的 credentials,如 omitsame-origin 或者 include。为了在当前域名内自动发送 cookie,必须提供这个选项,从 Chrome 50 开始,这个属性也可以接受 FederatedCredential 实例或是一个 PasswordCredential 实例。
  • cache: 请求的 cache 模式:defaultno-storereloadno-cacheforce-cache 或者 only-if-cached
  • redirect: 可用的 redirect 模式:follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误),或者 manual (手动处理重定向)。在 Chrome 中默认使用 follow(Chrome 47 之前的默认值是 manual)。
  • referrer: 一个 USVString 可以是 no-referrerclient 或一个 URL。默认是 client
  • referrerPolicy: 指定了 HTTP 头部 referer 字段的值。可能为以下值之一:no-referrerno-referrer-when-downgradeoriginorigin-when-cross-originunsafe-url
  • integrity: 包括请求的 subresource integrity 值(例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。

一个基本的 fetch 请求设置起来很简单。看看下面的代码:

fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data));

如上是一个简单的fetch请求,只设置了第一个参数。
接下来是设置第二个参数的fetch请求例子;

// Example POST method implementation:
async function postData(url = '', data = {}) {
  // Default options are marked with *
  try {
    const response = await fetch(url, {
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        mode: 'cors', // no-cors, *cors, same-origin
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'same-origin', // include, *same-origin, omit
        headers: {
          'Content-Type': 'application/json'
          // 'Content-Type': 'application/x-www-form-urlencoded',
        },
        redirect: 'follow', 
        referrerPolicy: 'no-referrer', 
        body: JSON.stringify(data)
      });
      return response.json(); 
  } catch (error) {
    console.log(error)
  }
  
}

postData('https://example.com/answer', { answer: 42 })
  .then(data => {
    console.log(data); // JSON data parsed by `data.json()` call
  });

注意:假如mode是no-cors,则允许使用一组有限的 HTTP 请求头:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type 允许使用的值为:application/x-www-form-urlencodedmultipart/form-datatext/plain

上传文件用法

可以通过 HTML <input type="file" /> 元素,FormData()fetch() 上传文件。

const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.then(result => {
  console.log('Success:', result);
})
.catch(error => {
  console.error('Error:', error);
});

以上,将获取到的文件数据组装到FormData对象里,然后由请求的body带给服务端。

上传多个文件的用法

可以通过 HTML <input type="file" multiple /> 元素,FormData()fetch() 上传文件。

const formData = new FormData();
const photos = document.querySelector('input[type="file"][multiple]');

formData.append('title', 'My Vegas Vacation');
for (let i = 0; i < photos.files.length; i++) {
  formData.append(`photos_${i}`, photos.files[i]);
}

fetch('https://example.com/posts', {
  method: 'POST',
  body: formData,
})
.then(response => response.json())
.then(result => {
  console.log('Success:', result);
})
.catch(error => {
  console.error('Error:', error);
});

多个文件的话,遍历组装进去即可。

Response对象

fetch()请求成功以后,得到的是一个 Response 对象。它对应服务器的 HTTP 回应。

Response有以下属性:

body

一个 ReadableStream,或者对于使用空的 body 属性构建的任意的 Response 对象,或没有任何主体的实际 HTTP 响应,则为 null

bodyUsed

一个只读属性。用以表示该 body 是否被使用过。

headers

包含与响应关联的Headers对象。

ok

包含一个布尔值,表明响应是否成功(状态码在 200-299 范围内).

redirected

表明该响应是否为一个重定向的请求的结果。

status

包含响应的状态代码(例如,成功为 200)。

statusText

包含与状态代码相对应的状态消息(例如,对于 200 可以确定)。

type

包含一种响应的类型。可能值如下:

  • basic:标准值,同源响应,暴露除了“Set-Cookie”之外的所有标头。
  • cors:从有效的跨源请求接收到响应。某些标头和主体可以被访问。
  • error:网络错误。没有有用的描述错误的信息。响应的状态为 0,header 为空且不可变。这是从 Response.error() 中获得的响应的类型。
  • opaque:对跨源资源的“no-cors”请求的响应。严格限制。
  • opaqueredirect:fetch 请求是通过 redirect: "manual" 发出的。响应的状态是 0,标头是空的,主体是 null,trailer 是空的。

url

返回请求的URL值,如果发生重定向,URL 属性的值将是在任何重定向之后获得的最终 URL。

Response对象读取的方法

arrayBuffer()

Response上的方法 arrayBuffer() 接受一个 Response 流,并等待其读取完成。它返回一个 promise 实例,并 resolve 一个 ArrayBuffer 对象。

response.arrayBuffer().then(function(buffer) {
  //
)};
function getData() {
  source = audioCtx.createBufferSource();

  var myRequest = new Request('viper.ogg');

  fetch(myRequest).then(function(response) {
    response.arrayBuffer().then(function(buffer) {
      audioCtx.decodeAudioData(buffer, function(decodedData) {
        source.buffer = decodedData;
        source.connect(audioCtx.destination);
      });
    });
  });
};


play.onclick = function() {
  getData();
  source.start(0);
  play.setAttribute('disabled', 'disabled');
}

blob()

从Response读取到blob。
如下例子:

var myImage = document.querySelector('img');

var myRequest = new Request('flowers.jpg');

fetch(myRequest)
.then(function(response) {
  return response.blob();
})
.then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

我们使用Request.Request构造方法创建了一个新的 request 对象,然后使用它来获取一个 JPG 文件。当 fetch 成功的时候,我们使用 blob() 从 response 中读取一个Blob对象,并使用URL.createObjectURL 将它放入一个 object URL,然后把 URL 设置为img元素的 src 属性以显示这张图片。

formData()

返回得到一个FormData对象。
response.formData()主要用在 Service Worker 里面,拦截用户提交的表单,修改某些数据以后,再提交给服务器。

json()

Response mixin 的 json() 方法接收一个 Response 流,并将其读取完成。它返回一个 Promise,Promise 的解析 resolve 结果是将文本体解析为 JSON

const myList = document.querySelector('ul');
const myRequest = new Request('products.json');

fetch(myRequest)
  .then(response => response.json())
  .then(data => {
    for (const product of data.products) {
      let listItem = document.createElement('li');
      listItem.appendChild(
        document.createElement('strong')
      ).textContent = product.Name;
      listItem.append(
        ` can be found in ${
          product.Location
        }. Cost: `
      );
      listItem.appendChild(
        document.createElement('strong')
      ).textContent = `£${product.Price}`;
      myList.appendChild(listItem);
    }
  });

以上是我们使用 Request.Request 构造函数创建一个新的请求,然后使用它来获取一个 .json 文件。当获取成功时,我们使用 json() 读取并解析数据,然后像预期的那样从结果对象中读取值,并将其插入到列表项中以显示我们的产品数据。

text()

Response mixin 的 text() 方法提供了一个可供读取的“返回流”(Response stream),并将它读取完。它返回一个包含 USVString 对象(也就是文本)的 Promise 对象,返回结果的编码永远是 UTF-8。
例子如下:

const myArticle = document.querySelector('article');
const myLinks   = document.querySelectorAll('ul a');

for(i = 0; i <= myLinks.length-1; i++) {
  myLinks[i].onclick = function(e) {
    e.preventDefault();
    var linkData = e.target.getAttribute('data-page');
    getData(linkData);
  }
};

function getData(pageId) {
  console.log(pageId);
  const myRequest = new Request(pageId + '.txt');
  fetch(myRequest).then(function(response) {
    return response.text().then(function(text) {
      myArticle.innerHTML = text;
    });
  });
}

我们使用 Request() 构造函数创建了一个请求(Request)对象,然后,使用它获取指定的.txt的文件,当 fetch 函数执行成功,我们使用 text() 函数来返回一个USVString (text) 对象,将它设置到 <article> 对象的innerHTML(元素文本)中。

clon()

Response 接口的 clone() 方法创建一个响应对象的克隆,这个对象在所有方面都是相同的,但是储存在不同的变量中。
如下例子:

const image1 = document.querySelector('.img1');
const image2 = document.querySelector('.img2');

const myRequest = new Request('flowers.jpg');

fetch(myRequest).then((response) => {
  const response2 = response.clone();

  response.blob().then((myBlob) => {
    const objectURL = URL.createObjectURL(myBlob);
    image1.src = objectURL;
  });

  response2.blob().then((myBlob) => {
    const objectURL = URL.createObjectURL(myBlob);
    image2.src = objectURL;
  });
});

我们使用 Request() 构造函数创建一个新的 Request 来传递一个 JPG 路径。然后我们使用 fetch() 获取这个请求。当 fetch 成功兑现时,我们克隆它,使用两个 Body.blob 调用从两个响应中提取 blob,使用 URL.createObjectURL 从 blob 创建对象 URL,并将它们显示在两个单独的 <img>元素中。

总结

以上就是关于Fetch API的详细解析。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值