fetch API / XMLHttpRequest 解读

fetch API / XMLHttpRequest 解读

🗨

在我们日常的前端开发中,XMLHttpRequest 是必不可少会遇到的一个东东。XHR 最初是由微软引入其 MSXML的,Web 开发者需要通过 ActiveX 去调用,而后,Mozilla 开发者开发了一个近似的东西,为了方便在 JavaScript 中使用,才用 XMLHttpRequest 为名的对象封装了一下。使用 XHR 发起一个请求,大致代码就会如下所示:

// 首先,需要些一些特征检测来做下浏览器兼容
if (window.XMLHttpRequest) {  
  request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
  try {
    request = new ActiveXObject('Msxml2.XMLHTTP');
  } 
  catch (e) {
    try {
      request = new ActiveXObject('Microsoft.XMLHTTP');
    } 
    catch (e) {}
  }
}

// 然后开启一个请求
request.open('GET', 'https://nodejs.org/api/http.json', true);  
// 真正意义上的请求
request.send(null);  
request.addEventListener('load', function() {  
    // 处理返回结果
})

以上的代码,相信每个前端开发都有写过,然而就算不写那一段长长的兼容代码,光是后面发起请求的那段代码,也会让人觉得头大。就更不用说所谓的 XMLHttpRequest,其实现在几乎没人用 XML 做浏览器短的数据交互形式了。

尽管众多三方框架已经封装了一些好用的 api,例如 jQuery.ajax(),angular.js 的 $http,但是如果有个更简单的方法呢?

Syntax

fetch() 的语法很简单,如下所示:

fetch(input, init).then(function(response) { ... });  

其中:

input 参数,即可以直接传入一个 url,也可以传入一个 Request 对象;

init 参数是可选,是一个包含了请求方法,请求头部,请求主体,模式,凭证,缓存模式等配置的对象。

从语法中可以看到,fetch() API 会返回一个 Promise。

因此,开头所提到的例子,可以修改成这样:

fetch('https://nodejs.org/api/http.json').then(function(response) {  
    return // 响应处理
}).catch(function(err) {
    // 捕获错误
});

除了普通的 get 请求,发起一个表单 POST 请求也是相当简单:

fetch('/post/some/data', {  
    method: 'post',
    body: new FormData(document.querySelector('#form'))
});

同理,如果是 json 格式的数据的话:

fetch('/post/some/data', {  
    method: 'post',
    body: JSON.stringify({ user: 'lisposter', pwd: 'souche.com'})
});

响应处理

与上述 Request 对应的,Fetch API 还对应有一个 Response 用于表示响应结果,Response,是一个 Stream 对象,其提供了众多便利的属性及方法以供开发者处理。方法一般会返回一个 Promise,举个例子,处理 json 数据。简单示例:

fetch('https://nodejs.org/api/http.json')  
    .then(function(response) {
        return response.json();
    })
    .then(function(json) {
        // 此处的 json 已经被处理为 json 对象
    })
    .catch(function(err) {
        // 捕获错误
    });

这里,你当然也可以选择使用传统的 JSON.parse(),但无疑,使用 .json() 方法更加方便快捷,适合在 Promise 中使用。

同理,如果你希望处理请求结果为纯文本,那么 Response.text() 将会很有帮助。除此之外,还有 .blob(), formData() 等方法可供使用。

从 Response 的属性中,我们也能轻易提取到响应头部及 Metadata 的相关信息

fetch('https://nodejs.org/api/http.json').then(function(response) {  
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.url);
    console.log(response.type);
    console.log(response.headers);

// 获取头部信息需要使用 .get() 
console.log(response.headers.get('Content-Type'));  
})

响应类型

每当我们用 fetch 发起一个请求,其响应都会被赋予一个响应类型,'basic','cors' 或者 'opaque'。

如果请求是同源的,那么响应类型就是 'basic',如果跨域的请求,则是 'cors',如果对非同源的资源发起一个请求,并且其没有返回 CORS 头的话,则是 'opaque' 类型。'opaque' 类型的响应我们将不能读取所返回的数据或者查看请求的状态,也就是说,我们压根没办法知道请求是否成功了。

我们可以在发起请求的时候,指定一个模式来确保只有相应的请求会被允许:

  • same-origin: 只有同源的请求才会被允许。
  • cors: 允许同源或者非同源但是返回正确 CORS 头部的请求。
  • cors-with-forced-preflight: 在正式请求之前,总是先发起一个 preflight 检查。
  • no-cors: 用以发起非同源又没有返回 CORS 头的请求。

注意:因为 Cache API 还没有在 window 对象中实现,因此,目前 fetch api 并没有支持从 window 域中发起非同源的请求。


频道:Web