1. 云栖社区>
  2. PHP教程>
  3. 正文

React Native系列——Fetch使用介绍

作者:用户 来源:互联网 时间:2017-12-01 19:12:34

nativereact使用fetch介绍系列

React Native系列——Fetch使用介绍 - 摘要: 本文讲的是React Native系列——Fetch使用介绍, 1、浏览器同策同源 可谓同源。URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。浏览器的同源策略,限制了来自不同源 的"document"或脚本,对当前"document"读取或设置某些属性,即从一


1、浏览器同策同源

可谓同源。URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。浏览器的同源策略,限制了来自不同源 的"document"或脚本,对当前"document"读取或设置某些属性,即从一个域上加载的脚本不允许访问另外一个域的文档属性。比如一个恶意网 站的页面通过iframe嵌入了银行的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取 用户名和密码。所谓道高一尺魔高一丈,虽然浏览器以同源策略限制了我们随意请求资源,但是从这个策略出现开始就有很多各种各样的Hacker技巧来。


2、四种跨域方法的实现

1、Jsonp


2、CORS:跨域资源共享


3、postMessage


具体原理和用法请参照:https://segmentfault.com/a/1190000006095018


3、Fetch介绍
3.1、Fetch定义

Fetch API提供了一个fetch()方法,它被定义在BOM的window对象中,你可以用它来发起对远程资源的请求。 该方法返回的是一个ES6的Promise对象,让你能够对请求的返回结果进行检索。 它是 W3C 的正式标准 。


3.2、Fetch所面临的阻力

Fetch API从提出到实现一直存在着争议,由于一直现存的历史原因(例如HTML5的拖拽API被认为太过稀疏平常,Web Components标准被指意义不大)。 因此重新设计一个新的API来替代久经沙场历练的XMLHttpRequest就变得阻力重重。


其中一种反对观点认为,Promises缺少了一些重要的XMLHttpRequest的使用场景。例如, 使用标准的ES6 Promise你无法收集进入信息或中断请求。而Fetch的狂热开发者更是试图提供Promise API的扩展用于取消一个Promise。 这个提议有点自挖墙角的意思,因为将这将让Promise变得不符合标准。但这个提议或许会导致未来出现一个可取消的Promise标准。 但另一方面,使用XMLHttpRequest你可以模拟进度(监听progress事件),也可以取消请求(使用abort()方法)。 但是,如果有必要你也可以使用Promise来包裹它。


另一种反对观点认为,Web平台需要的是更多底层的API,而不是高层的API。对此的回答恰恰是, Fetch API足够底层,因为当前的WHATWG标准定义了XMLHttpRequest.send()方法其实等同于fetch的Requset对象。 Fetch中的Response.body实现了getReader()方法用于渐增的读取原始字节流。 例如,如果照片列表过大而放不进内存的话,你可以使用下面的方法来处理:


function streamingDemo() {
var req = new Request(URL, {method: 'GET', cache: 'reload'});
fetch(req).then(function(response) {
var reader = response.body.getReader();
return reader.read();
}).then(function(result, done) {
if (!done) {
// do something with each chunk
}
});
}


在上面的代码中处理器函数一块一块的接收响应体,而不是一次性的。当数据全部被读完后会将done标记设置为true。 在这种方式下,每次你只需要处理一个chunk,而不是一次性的处理整个响应体。

3.3、Fetch的优点

1、语法简洁,更加语义化


2、基于标准 Promise 实现,支持 async/await


3、同构方便,使用 isomorphic-fetch


3.4、Fetch的不足

由于 Fetch 是典型的异步场景,所以大部分遇到的问题不是 Fetch 的,其实是 Promise 的。ES6 的 Promise 是基于 Promises/A+ 标准,为了保持 简单简洁 ,只提供极简的几个 API。如果你用过一些牛 X 的异步库,如 jQuery(不要笑) 、Q.js 或者 RSVP.js,可能会感觉 Promise 功能太少了。


(1)没有 Deferred


Deferred 可以在创建 Promise 时可以减少一层嵌套,还有就是跨方法使用时很方便。 ECMAScript 11 年就有过 Deferred 提案,但后来没被接受。其实用 Promise 不到十行代码就能实现 Deferred:es6-deferred。现在有了 async/await,generator/yield 后,deferred 就没有使用价值了。


(2)没有获取状态方法:isRejected,isResolved


标准 Promise 没有提供获取当前状态 rejected 或者 resolved 的方法。只允许外部传入成功或失败后的回调。我认为这其实是优点,这是一种声明式的接口,更简单。


(3)缺少其它一些方法:always,progress,finally


always 可以通过在 then 和 catch 里重复调用方法实现。finally 也类似。progress 这种进度通知的功能还没有用过,暂不知道如何替代。


(4)不能中断,没有 abort、terminate、onTimeout 或 cancel 方法


Fetch 和 Promise 一样,一旦发起,不能中断,也不会超时,只能等待被 resolve 或 reject。幸运的是,whatwg 目前正在尝试解决这个问题 whatwg/fetch#27


4、Fetch的使用
4.1、简单使用

(1)get请求


fetch("/data.json").then(function(res) {
// res instanceof Response == true.
if (res.ok) {
res.json().then(function(data) {
console.log(data.entries);
});
} else {
console.log("Looks like the response wasn't perfect, got status", res.status);
}
}, function(e) {
console.log("Fetch failed!", e);
});fetch('http://nero-zou.com/test.json')
.then((response) => {
if (response.ok) {
return response.json()
} else {
console.error('服务器繁忙,请稍后再试;/r/nCode:' + response.status)
}
})
.then((data) => {
console.log(data)
})
.catch((err)=> {
console.error(err)
})

(2)post请求


fetch('/users', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Hubot',
login: 'hubot',
})
})fetch("http://www.example.org/submit.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "firstName=Nikhil&favColor=blue&password=easytoguess"
}).then(function(res) {
if (res.ok) {
alert("Perfect! Your settings are saved.");
} else if (res.status == 401) {
alert("Oops! You are not authorized.");
}
}, function(e) {
alert("Error submitting form!");
});

(3)上传文件


var input = document.querySelector('input[type="file"]')
var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')
fetch('/avatars', {
method: 'post',
body: data
})
4.2、Fetch中的三个主要部分

Fetch 引入了 3 个接口,分别是 Headers,Request 和 Response。他们直接对应于的 HTTP 中相应的概念,但是基于隐私和安全考虑,也有些区别,例如支持 CORS 规则以及保证 cookies 不能被第三方获取。


4.2.1、Header

自定义请求头信息极大地增强了请求的灵活性。我们可以通过 new Headers() 来创建请求头:


Create an empty Headers instance
var headers = new Headers();// Add a few headers
headers.append('Content-Type', 'text/plain');
headers.append('X-My-Custom-Header', 'CustomValue');// Check, get, and set header values
headers.has('Content-Type'); // true
headers.get('Content-Type'); // "text/plain"
headers.set('Content-Type', 'application/json');// Delete a header
headers.delete('X-My-Custom-Header');// Add initial values
var headers = new Headers({
'Content-Type': 'text/plain',
'X-My-Custom-Header': 'CustomValue'
});
4.2.2、Request

1、Request对象代表了一次fetch请求中的请求体部分,你可以自定义Request对象:

method - 使用的HTTP动词,GET, POST, PUT, DELETE, HEAD


url - 请求地址,URL of the request


headers - 关联的Header对象


referrer - referrer


mode - 请求的模式,主要用于跨域设置,cors, no-cors, same-origin


credentials - 是否发送Cookie omit, same-origin


redirect - 收到重定向请求之后的操作,follow, error, manual


integrity - 完整性校验


cache - 缓存模式(default, reload, no-cache)


2、使用方式如下


var request = new Request('/users.json', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
})
});// Now use it!
fetch(request).then(function() { /* handle response */ });

3、Request对象中mode属性详细介绍


(1)same-origin


该模式很简单,如果一个请求是跨域的,那么将返回一个 error,这样确保所有的请求遵守同源策略。


var arbitraryUrl = document.getElementById("url-input").value;
fetch(arbitraryUrl, { mode: "same-origin" }).then(function(res) {
console.log("Response succeeded?", res.ok);
}, function(e) {
console.log("Please enter a same-origin URL!");
});

(2)no-cors


该模式允许来自 CDN 的脚本、其他域的图片和其他一些跨域资源,但是首先有个前提条件,就是请求的 method 只能是HEAD、GET 或 POST。此外,如果 ServiceWorkers 拦截了这些请求,它不能随意添加或者修改除这些之外 Header 属性。第三,JS 不能访问 Response 对象中的任何属性,这确保了跨域时 ServiceWorkers 的安全和隐私信息泄漏问题。


(3)cors


该模式通常用于跨域请求,用来从第三方提供的 API 获取数据。该模式遵守 CORS 协议,并只有有限的一些 Header 被暴露给 Response 对象,但是 body 是可读的。例如,获取一个 Flickr 最感兴趣的照片的清单:


var u = new URLSearchParams();
u.append('method', 'flickr.interestingness.getList');
u.append('api_key', '');
u.append('format', 'json');
u.append('nojsoncallback', '1');var apiCall = fetch('https://api.flickr.com/services/rest?' + u);apiCall.then(function(response) {
return response.json().then(function(json) {
// photo is a list of photos.
return json.photos.photo;
});
}).then(function(photos) {
photos.forEach(function(photo) {
console.log(photo.title);
});
});

你将无法从 Headers 中读取 Date 属性,因为 Flickr 在 Access-Control-Expose-Headers 中设置了不允许读取它。


response.headers.get("Date"); // null


另外,credentials 属性决定了是否可以跨域访问 cookie 。该属性与 XHR 的 withCredentials 标志相同,但是只有三个值,分别是 omit(默认)、same-origin 和 include。

Request 对象也提供了客户端缓存机制(caching hints)。这个属性还在安全复审阶段。Firefox 提供了这个属性,但目前还不起作用。


4.2.3、Response

fetch 返回的 then 方法有一个 response 参数,它是一个 Response 实例。


Response 有如下属性:

type - basic, cors
url
useFinalURL - 是否为最终地址
status - 状态码 (ex: 200, 404, etc.)
ok - 是否成功响应 (status in the range 200-299)
statusText - status code (ex: OK)
headers - 响应头

Response 有如下方法:

clone() - 复制一份response


error() - 返回一个与网络相关的错误


redirect() - 返回了一个可以重定向至某URL的response.


arrayBuffer() - 返回一个带有ArrayBuffer的Promise.


blob() - 返回一个带有Blob的Promise.


formData() - 返回一个带有FormData的Promise.


json() - 返回一个带有JSON格式对象的Promise.


text() - 返回一个带有文本的Promise.


5、Fetch的浏览器兼容

React Native系列——Fetch使用介绍


原生支持率并不高,幸运的是,引入下面这些 polyfill 后可以完美支持 IE8+ :

由于 IE8 是 ES3,需要引入 ES5 的 polyfill: es5-shim, es5-sham
引入 Promise 的 polyfill: es6-promise
引入 fetch 探测库:fetch-detector
引入 fetch 的 polyfill: fetch-ie8
可选:如果你还使用了 jsonp,引入 fetch-jsonp
可选:开启 Babel 的 runtime 模式,现在就使用 async/await

可以通过检查 Headers、Request、Response 或 fetch 在 window 或 worker 作用域中是否存在,来检查是否支持 Fetch API。


Fetch polyfill 的基本原理是探测是否存在 window.fetch 方法,如果没有则用 XHR 实现。这也是 github/fetch 的做法,但是有些浏览器(Chrome 45)原生支持 Fetch,但响应中有中文时会乱码,老外又不太关心这种问题,所以封装了 fetch-detector 和 fetch-ie8 只在浏览器稳定支持 Fetch 情况下才使用原生 Fetch。这些库现在 每天有几千万个请求都在使用,绝对靠谱 。

6、Fetch的服务端使用

用到了isomorphic-fetch这个库


// 自动进行全局的ES6 Promise的Polyfill
require('es6-promise').polyfill();
require('isomorphic-fetch');
7、参考文章

http://www.csdn.net/article/1970-01-01/2826065


https://github.com/camsong/blog/issues/2


http://www.tuicool.com/articles/M7NRr27 看


http://bubkoo.com/2015/05/08/introduction-to-fetch/ 看


https://segmentfault.com/a/1190000006095018#articleHeader14 看

免责说明

1、本博客中的文章摘自网上的众多博客,仅作为自己知识的补充和整理,并分享给其他需要的coder,不会用于商用。


2、因为很多博客的地址看完没有及时做保存,所以很多不会在这里标明出处,非常感谢各位大牛的分享,也希望大家理解。

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索native , react , 使用 , fetch , 介绍 系列 ,以便于您获取更多的相关知识。