reactjs fetch 跨域域该怎么写

学会fetch的用法 - 推酷
学会fetch的用法
fetch是web提供的一个可以获取异步资源的api,目前还没有被所有浏览器支持,它提供的api返回的是Promise对象,所以你在了解这个api前首先得了解Promise的用法。参考
那我们首先讲讲在没有fetch的时候,我们是如何获取异步资源的:
//发送一个get请求是这样的:
//首先实例化一个XMLHttpRequest对象
var httpRequest = new XMLHttpRequest();
//注册httpRequest.readyState改变时会回调的函数,httpRequest.
//readyState共有5个可能的值,
//0 UNSENT (未打开) open()方法还未被调用;
//1 OPENED
(未发送) send()方法还未被调用;
//2 HEADERS_RECEIVED (已获取响应头) send()方法已经被调用, 响应头和响应状态已经返回;
//3 LOADING (正在下载响应体) 响应体下载中; responseText中已经获取了部分数据;
//4 DONE (请求完成) 整个请求过程已经完毕.
httpRequest.onreadystatechange = function(){
//该回调函数会被依次调用4次
console.log(httpRequest.readyState);
if(httpRequest.readyState===4){
//请求已完成
if(httpRequest.status===200){
//http状态为200
console.log(httpRequest.response);
var data = JSON.parse(httpRequest.response);
console.log(data);
//请求的网址
var url = &http://127.0.0.1:7777/list&;
//该方法为初始化请求,第一个参数是请求的方法,比如GET,POST,PUT,第二个参数是请求的url
httpRequest.open('GET',url,true);
//设置http请求头
httpRequest.setRequestHeader(&Content-Type&,&application/json&);
//发出请求,参数为要发送的body体,如果是GET方法的话,一般无需发送body,设为空就可以
httpRequest.send(null);
关于XMLHttpRequest的更多用法请参照:
如果用了fetch之后,发送一个get请求是这样的:
//请求的网址
var url = &http://127.0.0.1:7777/list&;
//发起get请求
var promise = fetch(url).then(function(response) {
//response.status表示响应的http状态码
if(response.status === 200){
//json是返回的response提供的一个方法,会把返回的json字符串反序列化成对象,也被包装成一个Promise了
return response.json();
promise = promise.then(function(data){
//响应的内容
console.log(data);
}).catch(function(err){
console.log(err);
接下来介绍下fetch的语法:
input:定义要获取的资源。可能的值是:一个URL或者一个Request对象。
init:可选,是一个对象,参数有:
method: 请求使用的方法,如 GET、POST。
headers: 请求的头信息,形式为 Headers 对象或 ByteString。
body: 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
mode: 请求的模式,如 cors、 no-cors 或者 same-origin,默认为no-cors,该模式允许来自 CDN 的脚本、其他域的图片和其他一些跨域资源,但是首先有个前提条件,就是请求的 method 只能是HEAD、GET 或 POST。此外,如果 ServiceWorkers 拦截了这些请求,它不能随意添加或者修改除这些之外 Header 属性。第三,JS 不能访问 Response 对象中的任何属性,这确保了跨域时 ServiceWorkers 的安全和隐私信息泄漏问题。cors模式允许跨域请求,same-origin模式对于跨域的请求,将返回一个 error,这样确保所有的请求遵守同源策略。
credentials: 请求的 credentials,如 omit、same-origin 或者 include。
请求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.
返回值:一个 Promise,resolve 时回传 Response 对象。
fetch(input, init).then(function(response) {
一个发送post请求的示例:
fetch(&http://127.0.0.1:7777/postContent&, {
method: &POST&,
headers: {
&Content-Type&: &application/json&,
mode: &cors&,
body: JSON.stringify({
content: &留言内容&
}).then(function(res) {
if (res.status === 200) {
return res.json()
return Promise.reject(res.json())
}).then(function(data) {
console.log(data);
}).catch(function(err) {
console.log(err);
如果考虑低版本浏览器的问题的话,引入
即可兼容。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致浏览器跨域方法与基于Fetch的Web请求最佳实践 - WEB前端 - 伯乐在线
& 浏览器跨域方法与基于Fetch的Web请求最佳实践
本文从属于笔者的.
可谓同源?URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。浏览器的同源策略,限制了来自不同源的”document”或脚本,对当前”document”读取或设置某些属性,即从一个域上加载的脚本不允许访问另外一个域的文档属性。比如一个恶意网站的页面通过iframe嵌入了银行的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取用户名和密码。所谓道高一尺魔高一丈,虽然浏览器以同源策略限制了我们随意请求资源,但是从这个策略出现开始就有很多各种各样的Hacker技巧来。
JSONP是较为常用的一种跨域方式,不受到浏览器兼容性的限制,但是因为它只能以GET动词进行请求,这样就破坏了标准的REST风格,比较丑陋。JSONP本质上是利用&script&标签的跨域能力实现跨域数据的访问,请求动态生成的JavaScript脚本同时带一个callback函数名作为参数。其中callback函数本地文档的JavaScript函数,服务器端动态生成的脚本会产生数据,并在代码中以产生的数据为参数调用 callback函数。当这段脚本加载到本地文档时,callback函数就被调用。
(1)浏览器端构造请求地址
JavaScript
function resolveJson(result) {
console.log(result.name);
var jsonpScript= document.createElement("script");
jsonpScript.type = "text/javascript";
jsonpScript.src = "?callbackName=resolveJson";
document.getElementsByTagName("head")[0].appendChild(jsonpScript);
function resolveJson(result) {&&&&console.log(result.name);}var jsonpScript= document.createElement("script");jsonpScript.type = "text/javascript";jsonpScript.src = "?callbackName=resolveJson";document.getElementsByTagName("head")[0].appendChild(jsonpScript);
标准的Script标签的请求地址为:请求资源的地址+获取函数的字段名+回调函数名称,这里的获取函数的字段名是需要和服务端提前约定好,譬如jQuery中默认的获取函数名就是callback。而resolveJson是我们默认注册的回调函数,注意,该函数名需要全局唯一,该函数接收服务端返回的数据作为参数,而函数内容就是对于该参数的处理。
(2)服务端构造返回值
在接受到浏览器端 script 的请求之后,从url的query的callbackName获取到回调函数的名字,例子中是resolveJson。
然后动态生成一段javascript片段去给这个函数传入参数执行这个函数。比如:
JavaScript
resolveJson({name: 'qiutc'});
resolveJson({name: 'qiutc'});
(3)客户端以脚本方式执行服务端返回值
服务端返回这个 script 之后,浏览器端获取到 script 资源,然后会立即执行这个 javascript,也就是上面那个片段。这样就能根据之前写好的回调函数处理这些数据了。
跨域资源共享,Cross-Origin Resource Sharing是由W3C提出的一个用于浏览器以XMLHttpRequest方式向其他源的服务器发起请求的规范。不同于JSONP,CORS是以Ajax方式进行跨域请求,需要服务端与客户端的同时支持。目前CORS在绝大部分现代浏览器中都是支持的:
CORS标准定义了一个规范的HTTP Headers来使得浏览器与服务端之间可以进行协商来确定某个资源是否可以由其他域的客户端请求获得。尽管很多的验证与鉴权是由服务端完成,但是本质上大部分的检查和限制还是应该由浏览器完成。一般来说CORS会分为Simple Request,简单请求与Preflight,需要预检的请求两大类。其基本的流程如下:
当浏览器的请求方式是HEAD、GET或者POST,并且HTTP的头信息中不会超出以下字段:
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
时,浏览器会将该请求定义为简单请求,否则就是预检请求。预检请求会在正式通信之前,增加一次HTTP查询请求。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。预检请求的发送请求:
OPTIONS /cors HTTP/1.1
Origin: http://api.qiutc.me
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
OPTIONS /cors HTTP/1.1Origin: http://api.qiutc.meAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: X-Custom-HeaderHost: api.qiutc.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...
“预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。
除了Origin字段,”预检”请求的头信息包括两个特殊字段:
Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
预检请求的返回:
HTTP/1.1 200 OK
Date: Mon, 01 Dec :39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.qiutc.me
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/ charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
123456789101112
HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:15:39 GMTServer: Apache/2.0.61 (Unix)Access-Control-Allow-Origin: http://api.qiutc.meAccess-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderContent-Type: text/html; charset=utf-8Content-Encoding: gzipContent-Length: 0Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain
Access-Control-Allow-Methods:必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次”预检”请求。
Access-Control-Allow-Headers:如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。
Access-Control-Max-Age:该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
一旦服务器通过了”预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
对于简单的跨域请求或者通过了预检的请求,浏览器会自动在请求的头信息加上Origin字段,表示本次请求来自哪个源(协议 + 域名 + 端口),服务端会获取到这个值,然后判断是否同意这次请求并返回。典型的请求头尾:
JavaScript
GET /cors HTTP/1.1
Origin: http://api.qiutc.me
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
// 请求GET /cors HTTP/1.1Origin: http://api.qiutc.meHost: api.alice.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...
如果服务端允许,在返回的头信息中会多出几个字段:
JavaScript
Access-Control-Allow-Origin: http://api.qiutc.me
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Info
Content-Type: text/ charset=utf-8
// 返回Access-Control-Allow-Origin: http://api.qiutc.meAccess-Control-Allow-Credentials: trueAccess-Control-Expose-Headers: InfoContent-Type: text/html; charset=utf-8
Access-Control-Allow-Origin:必须。它的值是请求时Origin字段的值或者 *,表示接受任意域名的请求。
Access-Control-Allow-Credentials:可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。
再需要发送cookie的时候还需要注意要在AJAX请求中打开withCredentials属性:var xhr = new XMLHttpRequest(); xhr.withCredentials =
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为*,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
Access-Control-Expose-Headers:可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方
法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-
Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('Info')可以返回Info字段的值。
如果服务端拒绝了调用,即不会带上 Access-Control-Allow-Origin 字段,浏览器发现这个跨域请求的返回头信息没有该字段,就会抛出一个错误,会被 XMLHttpRequest 的 onerror 回调捕获到。这种错误无法通过 HTTP 状态码判断,因为回应的状态码有可能是200。
window.postMessage 是一个用于安全的使用跨源通信的方法。通常,不同页面上的脚本当且仅当执行它们的页面所处的位置使用相同的协议(通常都是 http)、相同的端口(http默认使用80端口)和相同的主机(两个页面的 document.domain 的值相同)只在这种情况下被允许互相访问。 而window.postMessage 提供了一个受控的机制来安全地绕过这一限制。其函数原型如下:
JavaScript
windowObj.postMessage(message, targetOrigin);
windowObj.postMessage(message, targetOrigin);
windowObj: 接受消息的 Window 对象。
message: 在最新的浏览器中可以是对象。
targetOrigin: 目标的源,* 表示任意。
调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 * 。需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。上面所说的向其他window对象发送消息,其实就是指一个页面有几个框架的那种情况,因为每一个框架都有一个window对象。在讨论第种方法的时候,我们说过,不同域的框架间是可以获取到对方的window对象的,虽然没什么用,但是有一个方法是可用的-window.postMessage。下面看一个简单的示例,有两个页面:
JavaScript
//在主页面中获取子页面的句柄
var iframe =document.getElementById('iframe');
var iframeWindow = iframe.contentW
//向子页面发送消息
iframeWindow.postMessage("I'm message from main page.");
//在子页面中监听获取消息
window.onmessage = function(e) {
console.log(e.data);
123456789101112
//在主页面中获取子页面的句柄&var iframe =document.getElementById('iframe');var iframeWindow = iframe.contentWindow;&//向子页面发送消息iframeWindow.postMessage("I'm message from main page.");//在子页面中监听获取消息window.onmessage = function(e) {&&&&e = e || event;&&&&console.log(e.data);}
使用代理方式跨域更加直接,因为SOP的限制是浏览器实现的。如果请求不是从浏览器发起的,就不存在跨域问题了。使用本方法跨域步骤如下:
把访问其它域的请求替换为本域的请求
本域的请求是服务器端的动态脚本负责转发实际的请求
不过笔者在自己的开发实践中发现目前服务端跨域还是很有意义的,特别当我们希望从不支持CORS或者JSONP的服务端获取数据的时候,往往只能通过跨域请求。
JavaScript 通过XMLHttpRequest(XHR)来执行异步请求,这个方式已经存在了很长一段时间。虽说它很有用,但它不是最佳API。它在设计上不符合职责分离原则,将输入、输出和用事件来跟踪的状态混杂在一个对象里。而且,基于事件的模型与最近JavaScript流行的Promise以及基于生成器的异步编程模型不太搭。新的 Fetch API打算修正上面提到的那些缺陷。 它向JS中引入和HTTP协议中同样的原语。具体而言,它引入一个实用的函数 fetch() 用来简洁捕捉从网络上检索一个资源的意图。Fetch 规范 的API明确了用户代理获取资源的语义。它结合ServiceWorkers,尝试达到以下优化:
改善离线体验
保持可扩展性
而与jQuery相比, fetch 方法与 jQuery.ajax() 的主要区别在于:
fetch()方法返回的Promise对象并不会在HTTP状态码为404或者500的时候自动抛出异常,而需要用户进行手动处理
默认情况下,fetch并不会发送任何的本地的cookie到服务端,注意,如果服务端依靠Session进行用户控制的话要默认开启Cookie
window.fetch是基于XMLHttpRequest的浏览器的统一的封装,针对老的浏览器可以使用Github的这个。fetch基于ES6的Promise,在旧的浏览器中首先需要引入Promise的polypill,可以用这个:
$ bower install es6-promise
$ bower install es6-promise
对于fetch的引入,可以用bower或者npm:
$ bower install fetch
$ npm install whatwg-fetch --save
$ bower install fetch$ npm install whatwg-fetch --save
如果是基于Webpack的项目,可以直接在Webpack的config文件中引入这种polyfill:
JavaScript
plugins: [
new webpack.ProvidePlugin({
'fetch': 'imports?this=&global!exports?global.fetch!whatwg-fetch'
plugins: [&&new webpack.ProvidePlugin({&&&&'fetch': 'imports?this=&global!exports?global.fetch!whatwg-fetch'&&})]
这个插件的配置主要依靠与,因此也需要导入它们:
$ npm i imports-loader exports-loader -S
$ npm i imports-loader exports-loader -S
如果感觉这种方式比较麻烦,也可以使用 :
npm install --save isomorphic-fetch es6-promise
bower install --save isomorphic-fetch es6-promise
npm install --save isomorphic-fetch es6-promisebower install --save isomorphic-fetch es6-promise
使用的时候也非常方便:
JavaScript
require('es6-promise').polyfill();
require('isomorphic-fetch');
fetch('//offline-news-/stories')
.then(function(response) {
if (response.status &= 400) {
throw new Error("Bad response from server");
return response.json();
.then(function(stories) {
console.log(stories);
123456789101112
require('es6-promise').polyfill();require('isomorphic-fetch');fetch('//offline-news-/stories')&&&&.then(function(response) {&&&&&&&&if (response.status &= 400) {&&&&&&&&&&&&throw new Error("Bad response from server");&&&&&&&&}&&&&&&&&return response.json();&&&&})&&&&.then(function(stories) {&&&&&&&&console.log(stories);&&&&});
从笔者自己的体验中,还是非常推荐使用isomorphic-fetch,其一大优势在于能够在node里直接进行单元测试与接口可用性测试。老实说笔者之前用Mocha进行带真实网络请求的测试时还是比较不方便的,往往需要在浏览器或者phatomjs中进行,并且需要额外的HTML代码。而在笔者的文件中,只需要直接使用babel-node model.test.js 即可以获取真实的网络请求,这样可以将网络测试部分与UI相剥离。
假设fetch已经被挂载到了全局的window目录下。
JavaScript
// Simple response handling
fetch('/some/url').then(function(response) {
}).catch(function(err) {
// Error :(
// Chaining for more "advanced" handling
fetch('/some/url').then(function(response) {
return //...
}).then(function(returnedValue) {
}).catch(function(err) {
// Error :(
123456789101112131415161718192021222324252627
// Simple response handling&fetch('/some/url').then(function(response) {&&&}).catch(function(err) {&&&&&// Error :(&});&// Chaining for more "advanced" handling&fetch('/some/url').then(function(response) {&&&&&return //...&}).then(function(returnedValue) {&&&&&// ...&}).catch(function(err) {&&&&&// Error :(&});
Request对象代表了一次fetch请求中的请求体部分,你可以自定义Request对象:
A Request instance represents the request piece of a fetch call. By passingfetch a Request you can make advanced and customized requests:
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)
JavaScript
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 */ });
123456789101112131415161718192021
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 */ });
JavaScript
fetch('/users.json', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
}).then(function() { /* handle response */ });
123456789101112131415
fetch('/users.json', {&&&&&method: 'POST', &&&&&mode: 'cors', &&&&&redirect: 'follow',&&&&&headers: new Headers({&&&&&&&&&'Content-Type': 'text/plain'&&&&&})&}).then(function() { /* handle response */ });
注意,fetch方法是自动会将URI中的双引号进行编码的,如果在URI中存入了部分JSON,有时候会出现意想不到的问题,譬如我们以GET方法访问如下的URI:
[GET] ?requestData={"p":"q"}
[GET] http://?requestData={"p":"q"}
那么fetch会自动将双引号编码,变成:
[GET] ?requestData={%22p%22:%22q%22}
[GET] http://?requestData={%22p%22:%22q%22}
那么这样一个请求传入到Spring MVC中时是会引发错误的,即URI对象构造失败这个很恶心的错误。笔者没有看过源代码,不过猜想会不会是Spring MVC看到{这个字符没有被编码,因此默认没有进行解码,结果没想到后面的双引号被编码了,为了避免这个无厘头的错误,笔者建议是对URI的Query Parameter部分进行统一的URI编码:
JavaScript
//将requestData序列化为JSON
var requestDataString = encodeURIComponent(JSON.stringify(requestData).replace(/%22/g, "\""));
//将字符串链接
const packagedRequestURL = `${Model.BASE_URL}${path}?requestData=${requestDataString}&action=${action}`;
//将requestData序列化为JSONvar requestDataString = encodeURIComponent(JSON.stringify(requestData).replace(/%22/g, "\""));//将字符串链接const packagedRequestURL = `${Model.BASE_URL}${path}?requestData=${requestDataString}&action=${action}`;
JavaScript
// 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'
123456789101112131415161718192021222324252627282930313233343536373839
// 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'&});
常见的请求方法有: append, has, get, set以及 delete
JavaScript
var request = new Request('/some-url', {
headers: new Headers({
'Content-Type': 'text/plain'
fetch(request).then(function() { /* handle response */ });
12345678910111213
var request = new Request('/some-url', {&&&&&headers: new Headers({&&&&&&&&&'Content-Type': 'text/plain'&&&&&})&});&&&fetch(request).then(function() { /* handle response */ });
JavaScript
fetch('/users', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
body: JSON.stringify({
name: 'Hubot',
login: 'hubot',
1234567891011
fetch('/users', {&&method: 'post',&&headers: {&&&&'Accept': 'application/json',&&&&'Content-Type': 'application/json'&&},&&body: JSON.stringify({&&&&name: 'Hubot',&&&&login: 'hubot',&&})})
JavaScript
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
12345678910
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})
如果需要设置fetch自动地发送本地的Cookie,需要将credentials设置为same-origin:
JavaScript
fetch('/users', {
credentials: 'same-origin'
fetch('/users', {&&credentials: 'same-origin'})
该选项会以类似于XMLHttpRequest的方式来处理Cookie,否则,可能因为没有发送Cookie而导致基于Session的认证出错。可以将credentials的值设置为include来在CORS情况下发送请求。
JavaScript
fetch(':1234/users', {
credentials: 'include'
fetch(':1234/users', {&&credentials: 'include'})
在fetch的then函数中提供了一个Response对象,即代表着对于服务端返回值的封装,你也可以在Mock的时候自定义Response对象,譬如在你需要使用Service Workers的情况下,在Response中,你可以作如下配置:
type – basic, cors
useFinalURL – 是否为最终地址
status – 状态码 (ex: 200, 404, etc.)
ok – 是否成功响应 (status in the range 200-299)
statusText – status code (ex: OK)
headers – 响应头
JavaScript
// Create your own response for service worker testing
// new Response(BODY, OPTIONS)
var response = new Response('.....', {
ok: false,
status: 404,
// The fetch's `then` gets a Response instance back
fetch('/')
.then(function(responseObj) {
console.log('status: ', responseObj.status);
12345678910111213141516171819202122232425
// Create your own response for service worker testing&// new Response(BODY, OPTIONS)&var response = new Response('.....', {&ok: false,&status: 404,&url: '/'&});&&&// The fetch's `then` gets a Response instance back&fetch('/')&.then(function(responseObj) {&console.log('status: ', responseObj.status);&});
The Response also provides the following methods:
clone() – Creates a clone of a Response object.
error() – Returns a new Response object associated with a network error.
redirect() – Creates a new response with a different URL.
arrayBuffer() – Returns a promise that resolves with an ArrayBuffer.
blob() – Returns a promise that resolves with a Blob.
formData() – Returns a promise that resolves with a FormData object.
json() – Returns a promise that resolves with a JSON object.
text() – Returns a promise that resolves with a USVString (text).
JavaScript
function checkStatus(response) {
if (response.status &= 200 && response.status & 300) {
return response
var error = new Error(response.statusText)
error.response = response
throw error
function parseJSON(response) {
return response.json()
fetch('/users')
.then(checkStatus)
.then(parseJSON)
.then(function(data) {
console.log('request succeeded with JSON response', data)
}).catch(function(error) {
console.log('request failed', error)
12345678910111213141516171819202122
function checkStatus(response) {&&if (response.status &= 200 && response.status & 300) {&&&&return response&&} else {&&&&var error = new Error(response.statusText)&&&&error.response = response&&&&throw error&&}}&function parseJSON(response) {&&return response.json()}&fetch('/users')&&.then(checkStatus)&&.then(parseJSON)&&.then(function(data) {&&&&console.log('request succeeded with JSON response', data)&&}).catch(function(error) {&&&&console.log('request failed', error)&&})
JavaScript
fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) {
// Convert to JSON
return response.json();
}).then(function(j) {
// Yay, `j` is a JavaScript object
console.log(j);
12345678910111213
fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { &// Convert to JSON&return response.json();&}).then(function(j) {&// Yay, `j` is a JavaScript object&console.log(j); &});
JavaScript
fetch('/next/page')
.then(function(response) {
return response.text();
}).then(function(text) {
// &!DOCTYPE ....
console.log(text);
12345678910111213
fetch('/next/page')&&&.then(function(response) {&&&&&return response.text();&&&}).then(function(text) { &&&// &!DOCTYPE ....&&&console.log(text); &&&});
如果你希望通过fetch方法来载入一些类似于图片等资源:
JavaScript
fetch('flowers.jpg')
.then(function(response) {
return response.blob();
.then(function(imageBlob) {
document.querySelector('img').src = URL.createObjectURL(imageBlob);
12345678910111213
fetch('flowers.jpg')&&&&&.then(function(response) {&&&&&&& return response.blob();&&&&&})&&&&&.then(function(imageBlob) {&&&&&&& document.querySelector('img').src = URL.createObjectURL(imageBlob);&});
blob()方法会接入一个响应流并且一直读入到结束。
笔者在自己的项目中封装了一个基于ES6 Class的基本的模型请求类,。
JavaScript
* Created by apple on 16/5/3.
//自动进行全局的ES6 Promise的Polyfill
require('es6-promise').polyfill();
require('isomorphic-fetch');
* &a href='/members/cmmol'&@function&/a& 基础的模型类,包含了基本的URL定义
export default class Model {
//默认的基本URL路径
static BASE_URL = "/";
//默认的请求头
static headers = {};
* &a href='/members/cmmol'&@function&/a& 默认构造函数
constructor() {
this._checkStatus = this._checkStatus.bind(this);
this._parseJSON = this._parseJSON.bind(this);
this._parseText = this._parseText.bind(this);
this._fetchWithCORS = this._fetchWithCORS.bind(this);
* &a href='/members/cmmol'&@function&/a& 检测返回值的状态
* @param response
* @returns {*}
_checkStatus(response) {
if (response.status &= 200 && response.status & 300) {
return response
var error = new Error(response.statusText);
error.response =
throw error
* &a href='/members/cmmol'&@function&/a& 解析返回值中的Response为JSON形式
* @param response
* @returns {*}
_parseJSON(response) {
if (!!response) {
return response.json();
* &a href='/members/cmmol'&@function&/a& 解析TEXT性质的返回
* @param response
* @returns {*}
_parseText(response) {
if (!!response) {
return response.text();
* &a href='/members/cmmol'&@function&/a& 封装好的跨域请求的方法
* @param packagedRequestURL
* @returns {*|Promise.&TResult&}
* &a href='/members/kaishu6296'&@private&/a&
_fetchWithCORS(packagedRequestURL, contentType) {
return fetch(packagedRequestURL, {
mode: "cors", headers: Model.headers
.then(this.checkStatus, (error)=& {
.then(contentType === "json" ? this._parseJSON : this._parseText, (error)=& {
* &a href='/members/cmmol'&@function&/a& 利用get方法发起请求
* @param path 请求的路径(包括路径参数)
* @param requestData 请求的参数
* @param action 请求的类型
* @param contentType 返回的类型
* @returns {Promise.&TResult&|*} Promise.then((data)=&{},(error)=&{});
get({BASE_URL=Model.BASE_URL, path="/", action="GET", contentType="json"}) {
//封装最终待请求的字符串
const packagedRequestURL = `${BASE_URL}${(path)}?action=${action}`;
//以CORS方式发起请求
return this._fetchWithCORS(packagedRequestURL, contentType);
* &a href='/members/cmmol'&@function&/a& 利用get方法与封装好的QueryParams形式发起请求
* @param path 请求的路径(包括路径参数)
* @param requestData 请求的参数
* @param action 请求的类型
* @returns {Promise.&TResult&|*} Promise.then((data)=&{},(error)=&{});
getWithQueryParams({BASE_URL=Model.BASE_URL, path="/", queryParams={}, action="GET", contentType="json"}) {
//初始化查询字符串
let queryString = "";
//根据queryParams构造查询字符串
for (let key in queryParams) {
//注意,请求参数必须进行URI格式编码,如果是JSON等特殊格式需要在服务端进行解码
queryString += `${key}=${encodeURIComponent(queryParams[key])}&`;
//将查询字符串进行编码
let encodedQueryString = (queryString);
//封装最终待请求的字符串
const packagedRequestURL = `${BASE_URL}${path}?${encodedQueryString}action=${action}`;
//以CORS方式发起请求
return this._fetchWithCORS(packagedRequestURL, contentType);
* &a href='/members/cmmol'&@function&/a& 利用get方法与封装好的RequestData形式发起请求
* @param path 请求的路径(包括路径参数)
* @param requestData 请求的参数
* @param action 请求的类型
* @returns {Promise.&TResult&|*} Promise.then((data)=&{},(error)=&{});
getWithRequestData({path="/", requestData={}, action="GET", contentType="json"}) {
//将requestData序列化为JSON
//注意要对序列化后的数据进行URI编码
var requestDataString = encodeURIComponent(JSON.stringify(requestData));
//将字符串链接
const packagedRequestURL = `${Model.BASE_URL}${path}?requestData=${requestDataString}&action=${action}`;
return this._fetchWithCORS(packagedRequestURL, contentType);
* &a href='/members/cmmol'&@function&/a& 考虑到未来post会有不同的请求方式,因此做区分处理
* @param path
* @param requestData
* @param action
* @returns {Promise.&TResult&|*}
postWithRequestData({path="/", requestData={}, action="POST", contentType="json"}) {
//将requestData序列化为JSON
//注意要对序列化后的数据进行URI编码
var requestDataString = encodeURIComponent(JSON.stringify(requestData));
//将字符串链接
const packagedRequestURL = `${Model.BASE_URL}${path}?requestData=${requestDataString}&action=${action}`;
return this._fetchWithCORS(packagedRequestURL, contentType);
put({path="/", requestData={}, action="put", contentType="json"}) {
delete({path="/", requestData={}, action="DELETE", contentType="json"}) {
Model.testData = {};
Model.testData.error = {};
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
/**& * Created by apple on 16/5/3.& */&//自动进行全局的ES6 Promise的Polyfill&require('es6-promise').polyfill();&require('isomorphic-fetch');&&&&&/**& * &a href='/members/cmmol'&@function&/a& 基础的模型类,包含了基本的URL定义& */&export default class Model {&&&&&&&&&//默认的基本URL路径&&&&&static BASE_URL = "/";&&&&&&&//默认的请求头&&&&&static headers = {};&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 默认构造函数&&&&& */&&&&&constructor() {&&&&&&&&&&&this._checkStatus = this._checkStatus.bind(this);&&&&&&&&&&&this._parseJSON = this._parseJSON.bind(this);&&&&&&&&&&&this._parseText = this._parseText.bind(this);&&&&&&&&&&&this._fetchWithCORS = this._fetchWithCORS.bind(this);&&&&&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 检测返回值的状态&&&&& * @param response&&&&& * @returns {*}&&&&& */&&&&&_checkStatus(response) {&&&&&&&&&&&if (response.status &= 200 && response.status & 300) {&&&&&&&&&&&&&return response&&&&&&&&&} else {&&&&&&&&&&&&&var error = new Error(response.statusText);&&&&&&&&&&&&&error.response = response;&&&&&&&&&&&&&throw error&&&&&&&&&}&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 解析返回值中的Response为JSON形式&&&&& * @param response&&&&& * @returns {*}&&&&& */&&&&&_parseJSON(response) {&&&&&&&&&&&if (!!response) {&&&&&&&&&&&&&&&return response.json();&&&&&&&&&}&&&&&&&&&else {&&&&&&&&&&&&&return undefined;&&&&&&&&&}&&&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 解析TEXT性质的返回&&&&& * @param response&&&&& * @returns {*}&&&&& */&&&&&_parseText(response) {&&&&&&&&&&&if (!!response) {&&&&&&&&&&&&&&&return response.text();&&&&&&&&&}&&&&&&&&&else {&&&&&&&&&&&&&return undefined;&&&&&&&&&}&&&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 封装好的跨域请求的方法&&&&& * @param packagedRequestURL&&&&& * @returns {*|Promise.&TResult&}&&&&& * &a href='/members/kaishu6296'&@private&/a&&&&&& */&&&&&_fetchWithCORS(packagedRequestURL, contentType) {&&&&&&&&&&&return fetch(packagedRequestURL, {&&&&&&&&&&&&&mode: "cors", headers: Model.headers&&&&&&&&&})&&&&&&&&&&&&&.then(this.checkStatus, (error)=& {&&&&&&&&&&&&&&&&&return error;&&&&&&&&&&&&&})&&&&&&&&&&&&&.then(contentType === "json" ? this._parseJSON : this._parseText, (error)=& {&&&&&&&&&&&&&&&&&return error;&&&&&&&&&&&&&});&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 利用get方法发起请求&&&&& * @param path 请求的路径(包括路径参数)&&&&& * @param requestData 请求的参数&&&&& * @param action 请求的类型&&&&& * @param contentType 返回的类型&&&&& * @returns {Promise.&TResult&|*} Promise.then((data)=&{},(error)=&{});&&&&& */&&&&&get({BASE_URL=Model.BASE_URL, path="/", action="GET", contentType="json"}) {&&&&&&&&&&&//封装最终待请求的字符串&&&&&&&&&const packagedRequestURL = `${BASE_URL}${(path)}?action=${action}`;&&&&&&&&&&&//以CORS方式发起请求&&&&&&&&&return this._fetchWithCORS(packagedRequestURL, contentType);&&&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 利用get方法与封装好的QueryParams形式发起请求&&&&& * @param path 请求的路径(包括路径参数)&&&&& * @param requestData 请求的参数&&&&& * @param action 请求的类型&&&&& * @returns {Promise.&TResult&|*} Promise.then((data)=&{},(error)=&{});&&&&& */&&&&&getWithQueryParams({BASE_URL=Model.BASE_URL, path="/", queryParams={}, action="GET", contentType="json"}) {&&&&&&&&&&&&&//初始化查询字符串&&&&&&&&&let queryString = "";&&&&&&&&&&&//根据queryParams构造查询字符串&&&&&&&&&for (let key in queryParams) {&&&&&&&&&&&&&&&//注意,请求参数必须进行URI格式编码,如果是JSON等特殊格式需要在服务端进行解码&&&&&&&&&&&&&queryString += `${key}=${encodeURIComponent(queryParams[key])}&`;&&&&&&&&&&&}&&&&&&&&&&&//将查询字符串进行编码&&&&&&&&&let encodedQueryString = (queryString);&&&&&&&&&&&//封装最终待请求的字符串&&&&&&&&&const packagedRequestURL = `${BASE_URL}${path}?${encodedQueryString}action=${action}`;&&&&&&&&&&&//以CORS方式发起请求&&&&&&&&&return this._fetchWithCORS(packagedRequestURL, contentType);&&&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 利用get方法与封装好的RequestData形式发起请求&&&&& * @param path 请求的路径(包括路径参数)&&&&& * @param requestData 请求的参数&&&&& * @param action 请求的类型&&&&& * @returns {Promise.&TResult&|*} Promise.then((data)=&{},(error)=&{});&&&&& */&&&&&getWithRequestData({path="/", requestData={}, action="GET", contentType="json"}) {&&&&&&&&&&&//将requestData序列化为JSON&&&&&&&&&//注意要对序列化后的数据进行URI编码&&&&&&&&&var requestDataString = encodeURIComponent(JSON.stringify(requestData));&&&&&&&&&&&//将字符串链接&&&&&&&&&const packagedRequestURL = `${Model.BASE_URL}${path}?requestData=${requestDataString}&action=${action}`;&&&&&&&&&&&return this._fetchWithCORS(packagedRequestURL, contentType);&&&&&&&}&&&&&&&/**&&&&& * &a href='/members/cmmol'&@function&/a& 考虑到未来post会有不同的请求方式,因此做区分处理&&&&& * @param path&&&&& * @param requestData&&&&& * @param action&&&&& * @returns {Promise.&TResult&|*}&&&&& */&&&&&postWithRequestData({path="/", requestData={}, action="POST", contentType="json"}) {&&&&&&&&&&&//将requestData序列化为JSON&&&&&&&&&//注意要对序列化后的数据进行URI编码&&&&&&&&&var requestDataString = encodeURIComponent(JSON.stringify(requestData));&&&&&&&&&&&//将字符串链接&&&&&&&&&const packagedRequestURL = `${Model.BASE_URL}${path}?requestData=${requestDataString}&action=${action}`;&&&&&&&&&&&return this._fetchWithCORS(packagedRequestURL, contentType);&&&&&}&&&&&&&put({path="/", requestData={}, action="put", contentType="json"}) {&&&&&&&}&&&&&&&&&delete({path="/", requestData={}, action="DELETE", contentType="json"}) {&&&&&&&}&&&}&&&&&Model.testData = {};&&&Model.testData.error = {};
可能感兴趣的话题
关于伯乐前端
伯乐前端分享Web前端开发,包括JavaScript,CSS和HTML5开发技术,前端相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线}

我要回帖

更多关于 fetch jsonp 跨域 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信