XMLHttpRequest第一版,只能对onreadystatechange
这一个事件指定回调函数。该事件对所有情况作出响应。 XMLHttpRequest第二版允许对更多的事件指定回调函数。
abort()
方法xhr.onload = function() {
var responseText = xhr.responseText;
console.log(responseText);
// process the response.
};
xhr.onerror = function() {
console.log('There was an error!');
};
注意,如果发生网络错误(比如服务器无法连通),onerror
事件无法获取报错信息,所以只能显示报错。
withCredentials
属性是一个布尔值,表示跨域请求时,用户信息(比如Cookie和认证的HTTP头信息)是否会包含在请求之中,默认为false
。即向example.com
发出跨域请求时,不会发送example.com
设置在本机上的Cookie(如果有的话)。
如果你需要通过跨域AJAX发送Cookie,需要打开withCredentials
。
xhr.withCredentials = true;
为了让这个属性生效,服务器必须显式返回Access-Control-Allow-Credentials
这个头信息。
Access-Control-Allow-Credentials: true
.withCredentials
属性打开的话,不仅会发送Cookie,还会设置远程主机指定的Cookie。注意,此时你的脚本还是遵守同源政策,无法 从document.cookie
或者HTTP回应的头信息之中,读取这些Cookie。
abort
方法用来终止已经发出的HTTP请求。
ajax.open('GET', 'http://www.example.com/page.php', true);
var ajaxAbortTimer = setTimeout(function() {
if (ajax) {
ajax.abort();
ajax = null;
}
}, 5000);
上面代码在发出5秒之后,终止一个AJAX请求。
getAllResponseHeaders
方法返回服务器发来的所有HTTP头信息。格式为字符串,每个头信息之间使用CRLF
分隔,如果没有受到服务器回应,该属性返回null
。
getResponseHeader
方法返回HTTP头信息指定字段的值,如果还没有收到服务器回应或者指定字段不存在,则该属性为null
。
function getHeaderTime () {
console.log(this.getResponseHeader("Last-Modified"));
}
var oReq = new XMLHttpRequest();
oReq.open("HEAD", "yourpage.html");
oReq.onload = getHeaderTime;
oReq.send();
如果有多个字段同名,则它们的值会被连接为一个字符串,每个字段之间使用“逗号+空格”分隔。
XMLHttpRequest
对象的open
方法用于指定发送HTTP请求的参数,它的使用格式如下,一共可以接受五个参数。
void open(
string method,
string url,
optional boolean async,
optional string user,
optional string password
);
method
:表示HTTP动词,比如“GET”、“POST”、“PUT”和“DELETE”。url
: 表示请求发送的网址。async
: 格式为布尔值,默认为true
,表示请求是否为异步。如果设为false
,则send()
方法只有等到收到服务器返回的结果,才会有返回值。user
:表示用于认证的用户名,默认为空字符串。password
:表示用于认证的密码,默认为空字符串。如果对使用过open()
方法的请求,再次使用这个方法,等同于调用abort()
。
下面发送POST请求的例子。
xhr.open('POST', encodeURI('someURL'));
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {};
xhr.send(encodeURI('dataString'));
上面方法中,open方法向指定URL发出POST请求,send方法送出实际的数据。
下面是一个同步AJAX请求的例子。
var request = new XMLHttpRequest();
request.open('GET', '/bar/foo.txt', false);
request.send(null);
if (request.status === 200) {
console.log(request.responseText);
}
send
方法用于实际发出HTTP请求。如果不带参数,就表示HTTP请求只包含头信息,也就是只有一个URL,典型例子就是GET请求;如果带有参数,就表示除了头信息,还带有包含具体数据的信息体,典型例子就是POST请求。
ajax.open('GET'
, 'http://www.example.com/somepage.php?id=' + encodeURIComponent(id)
, true
);
// 等同于
var data = 'id=' + encodeURIComponent(id));
ajax.open('GET', 'http://www.example.com/somepage.php', true);
ajax.send(data);
上面代码中,GET
请求的参数,可以作为查询字符串附加在URL后面,也可以作为send
方法的参数。
下面是发送POST请求的例子。
var data = 'email='
+ encodeURIComponent(email)
+ '&password='
+ encodeURIComponent(password);
ajax.open('POST', 'http://www.example.com/somepage.php', true);
ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
ajax.send(data);
如果请求是异步的(默认为异步),该方法在发出请求后会立即返回。如果请求为同步,该方法只有等到收到服务器回应后,才会返回。
注意,所有XMLHttpRequest的监听事件,都必须在send()
方法调用之前设定。
send
方法的参数就是发送的数据。多种格式的数据,都可以作为它的参数。
void send();
void send(ArrayBufferView data);
void send(Blob data);
void send(Document data);
void send(String data);
void send(FormData data);
如果发送Document
数据,在发送之前,数据会先被串行化。
发送二进制数据,最好使用ArrayBufferView
或Blob
对象,这使得通过Ajax上传文件成为可能。
下面是一个上传ArrayBuffer
对象的例子。
function sendArrayBuffer() {
var xhr = new XMLHttpRequest();
var uInt8Array = new Uint8Array([1, 2, 3]);
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(uInt8Array.buffer);
}
FormData类型可以用于构造表单数据。
var formData = new FormData();
formData.append('username', '张三');
formData.append('email', '[email protected]');
formData.append('birthDate', 1940);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/register");
xhr.send(formData);
上面的代码构造了一个formData
对象,然后使用send方法发送。它的效果与点击下面表单的submit按钮是一样的。
<form id='registration' name='registration' action='/register'>
<input type='text' name='username' value='张三'>
<input type='email' name='email' value='[email protected]'>
<input type='number' name='birthDate' value='1940'>
<input type='submit' onclick='return sendForm(this.form);'>
</form>
FormData也可以将现有表单构造生成。
var formElement = document.querySelector("form");
var request = new XMLHttpRequest();
request.open("POST", "submitform.php");
request.send(new FormData(formElement));
FormData对象还可以对现有表单添加数据,这为我们操作表单提供了极大的灵活性。
function sendForm(form) {
var formData = new FormData(form);
formData.append('csrf', 'e69a18d7db1286040586e6da1950128c');
var xhr = new XMLHttpRequest();
xhr.open('POST', form.action, true);
xhr.onload = function(e) {
// ...
};
xhr.send(formData);
return false;
}
var form = document.querySelector('#registration');
sendForm(form);
FormData对象也能用来模拟File控件,进行文件上传。
function uploadFiles(url, files) {
var formData = new FormData();
for (var i = 0, file; file = files[i]; ++i) {
formData.append(file.name, file); // 可加入第三个参数,表示文件名
}
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onload = function(e) { ... };
xhr.send(formData); // multipart/form-data
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
uploadFiles('/server', this.files);
}, false);
FormData也可以加入JavaScript生成的文件。
// 添加JavaScript生成的文件
var content = '<a id="a"><b id="b">hey!</b></a>';
var blob = new Blob([content], { type: "text/xml"});
formData.append("webmasterfile", blob);
setRequestHeader
方法用于设置HTTP头信息。该方法必须在open()
之后、send()
之前调用。如果该方法多次调用,设定同一个字段,则每一次调用的值会被合并成一个单一的值发送。
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
xhr.send(JSON.stringify(data));
上面代码首先设置头信息Content-Type
,表示发送JSON格式的数据;然后设置Content-Length
,表示数据长度;最后发送JSON数据。
该方法用来指定服务器返回数据的MIME类型。该方法必须在send()
之前调用。
传统上,如果希望从服务器取回二进制数据,就要使用这个方法,人为将数据类型伪装成文本数据。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
// 强制将MIME改为文本类型
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e) {
if (this.readyState == 4 && this.status == 200) {
var binStr = this.responseText;
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
var byte = c & 0xff; // 去除高位字节,留下低位字节
}
}
};
xhr.send();
上面代码中,因为传回来的是二进制数据,首先用xhr.overrideMimeType
方法强制改变它的MIME类型,伪装成文本数据。字符集必需指定为“x-user-defined”,如果是其他字符集,浏览器内部会强制转码,将其保存成UTF-16的形式。字符集“x-user-defined”其实也会发生转码,浏览器会在每个字节前面再加上一个字节(0xF700-0xF7ff),因此后面要对每个字符进行一次与运算(&),将高位的8个位去除,只留下低位的8个位,由此逐一读出原文件二进制数据的每个字节。
这种方法很麻烦,在XMLHttpRequest版本升级以后,一般采用指定responseType
的方法。
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
var arraybuffer = xhr.response;
// ...
}
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.send();
readyState
属性的值发生改变,就会触发readyStateChange事件。
我们可以通过onReadyStateChange
属性,指定这个事件的回调函数,对不同状态进行不同处理。尤其是当状态变为4的时候,表示通信成功,这时回调函数就可以处理服务器传送回来的数据。
上传文件时,XMLHTTPRequest对象的upload属性有一个progress,会不断返回上传的进度。
假定网页上有一个progress元素。
<progress min="0" max="100" value="0">0% complete</progress>
文件上传时,对upload属性指定progress事件回调函数,即可获得上传的进度。
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));
load事件表示服务器传来的数据接收完毕,error事件表示请求出错,abort事件表示请求被中断。
var xhr = new XMLHttpRequest();
xhr.addEventListener("progress", updateProgress);
xhr.addEventListener("load", transferComplete);
xhr.addEventListener("error", transferFailed);
xhr.addEventListener("abort", transferCanceled);
xhr.open();
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = oEvent.loaded / oEvent.total;
// ...
} else {
// 回应的总数据量未知,导致无法计算百分比
}
}
function transferComplete(evt) {
console.log("The transfer is complete.");
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}
abort
、load
和error
这三个事件,会伴随一个loadend
事件,表示请求结束,但不知道其是否成功。
req.addEventListener("loadend", loadEnd);
function loadEnd(e) {
alert("请求结束(不知道是否成功)");
}
HTML网页的<form>
元素能够以四种格式,向服务器发送数据。
POST
方法,将enctype
属性设为application/x-www-form-urlencoded
,这是默认方法。<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
</form>
POST
方法,将enctype
属性设为text/plain
。<form action="register.php" method="post" enctype="text/plain" onsubmit="AJAXSubmit(this); return false;">
</form>
POST
方法,将enctype
属性设为multipart/form-data
。<form action="register.php" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;">
</form>
GET
方法,enctype
属性将被忽略。<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
</form>
某个表单有两个字段,分别是foo
和baz
,其中foo
字段的值等于bar
,baz
字段的值一个分为两行的字符串。上面四种方法,都可以将这个表单发送到服务器。
第一种方法是默认方法,POST发送,Encoding type为application/x-www-form-urlencoded。
Content-Type: application/x-www-form-urlencoded foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
第二种方法是POST发送,Encoding type为text/plain。
Content-Type: text/plain
foo=bar
baz=The first line.
The second line.
第三种方法是POST发送,Encoding type为multipart/form-data。
Content-Type: multipart/form-data; boundary=---------------------------314911788813839 -----------------------------314911788813839 Content-Disposition: form-data; name="foo" bar -----------------------------314911788813839 Content-Disposition: form-data; name="baz" The first line. The second line. -----------------------------314911788813839--
第四种方法是GET请求。
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
通常,我们使用file控件实现文件上传。
<form id="file-form" action="handler.php" method="POST">
<input type="file" id="file-select" name="photos[]" multiple/>
<button type="submit" id="upload-button">上传</button>
</form>
上面HTML代码中,file控件的multiple属性,指定可以一次选择多个文件;如果没有这个属性,则一次只能选择一个文件。
file对象的files属性,返回一个FileList对象,包含了用户选中的文件。
var fileSelect = document.getElementById('file-select');
var files = fileSelect.files;
然后,新建一个FormData对象的实例,用来模拟发送到服务器的表单数据,把选中的文件添加到这个对象上面。
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.type.match('image.*')) {
continue;
}
formData.append('photos[]', file, file.name);
}
上面代码中的FormData对象的append方法,除了可以添加文件,还可以添加二进制对象(Blob)或者字符串。
// Files
formData.append(name, file, filename);
// Blobs
formData.append(name, blob, filename);
// Strings
formData.append(name, value);
append方法的第一个参数是表单的控件名,第二个参数是实际的值,第三个参数是可选的,通常是文件名。
最后,使用Ajax方法向服务器上传文件。
var xhr = new XMLHttpRequest();
xhr.open(‘POST’, ‘handler.php’, true);
xhr.onload = function () {
if (xhr.status !== 200) {
alert(‘An error occurred!’);
}
};
xhr.send(formData);
目前,各大浏览器(包括IE 10)都支持Ajax上传文件。
除了使用FormData接口上传,也可以直接使用File API上传。
var file = document.getElementById('test-input').files[0];
var xhr = new XMLHttpRequest();
xhr.open('POST', 'myserver/uploads');
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);
可以看到,上面这种写法比FormData的写法,要简单很多。
Ajax操作所用的XMLHttpRequest
对象,已经有十多年的历史,它的API设计并不是很好,输入、输出、状态都在同一个接口管理,容易写出非常混乱的代码。Fetch API是一种新规范,用来取代XMLHttpRequest
对象。它主要有两个特点,一是接口合理化,Ajax是将所有不同性质的接口都放在XHR对象上,而Fetch是将它们分散在几个不同的对象上,设计更合理;二是Fetch操作返回Promise
对象,避免了嵌套的回调函数。
下面的代码检查浏览器是否部署了Fetch API。
if (fetch in window){
// 支持
} else {
// 不支持
}
下面是一个Fetch API的简单例子。
fetch(url).then(function (response) {
return response.json();
}).then(function (jsonData) {
console.log(jsonData);
}).catch(function () {
console.log('出错了');
});
上面代码向指定的URL发出请求,得到回应后,将其转为JSON格式,输出到控制台。如果出错,则输出一条提示信息。注意,fetch
方法返回的是一个Promise对象。
作为比较,XMLHttpRequest
的写法如下。
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';
xhr.onload = function() {
console.log(xhr.response);
};
xhr.onerror = function() {
console.log('出错了');
};
xhr.send();
Fetch API最大的特点是,除了返回Promise
对象,还有一点就是数据传送是以数据流(stream)的形式进行的。对于大文件,数据是一段一段得到的。
response.text().then(function (responseText) {
console.log(responseText);
}
上面代码中的text()
,其实就是一个数据流读取器,并使用指定格式解读。
Fetch API提供以下五个数据流读取器。
.text()
:返回字符串.json()
:返回一个JSON对象.formData()
:返回一个FormData
对象.blob()
:返回一个blob
对象.arrayBuffer()
:返回一个二进制数组数据流只能读取一次,一旦读取,数据流就空了。再次读取就不会得到结果。解决方法是在读取之前,先使用.clone()
方法,复制一份一模一样的副本。
var url = 'LargeFile.txt';
var progress = 0;
var contentLength = 0;
fetch(url).then(function (response) {
// 本次请求总的数据长度
contentLength = response.headers.get('Content-Length');
var getStream = function (reader) {};
return getStream(response.body.getReader());
})
.catch(function (error) {
console.log(error);
});
上面代码中,response.body.getReader()
返回的就是数据流之中的一段。处理数据流的getStream
函数代码如下。
var progress = 0;
var contentLength = 0;
var getStream = function (reader) {
return reader.read().then(function (result) {
// 如果数据已经读取完毕,直接返回
if (result.done) {
return;
}
// 取出本段数据(二进制格式)
var chunk = result.value;
var text = '';
// 假定数据是UTF-8编码,前三字节是数据头,
// 而且每个字符占据一个字节(即都为英文字符)
for (var i = 3; i < chunk.byteLength; i++) {
text += String.fromCharCode(chunk[i]);
}
// 将本段数据追加到网页之中
document.getElementById('content').innerHTML += text;
// 计算当前进度
progress += chunk.byteLength;
console.log(((progress / contentLength) * 100) + '%');
// 递归处理下一段数据
return getStream(reader);
};
};
上面这样的数据流处理,可以提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。传统的XMLHTTPRequest
对象不支持数据流,所有的数据必须放在缓存里,等到全部拿到后,再一次性吐出来。
fetch
方法的第一个参数可以是URL字符串,也可以是后文要讲到的Request
对象实例。Fetch
方法返回一个Promise
对象,并将一个response
对象传给回调函数。
response
对象有一个ok
属性,如果返回的状态码在200到299之间(即请求成功),这个属性为true
,否则为false
。因此,判断请求是否成功的代码可以写成下面这样。
fetch('./api/some.json').then(function (response) {
if (response.ok) {
response.json().then(function (data) {
console.log(data);
});
} else {
console.log('请求失败,状态码为', response.status);
}
}, function(err) {
console.log('出错:', err);
});
response
对象除了json
方法,还包含了服务器HTTP回应的元数据。
fetch('users.json').then(function(response) {
console.log(response.headers.get('Content-Type'));
console.log(response.headers.get('Date'));
console.log(response.status);
console.log(response.statusText);
console.log(response.type);
console.log(response.url);
});
上面代码中,response
对象有很多属性,其中的response.type
属性比较特别,表示HTTP回应的类型,它有以下三个值。
如果需要在CORS机制下发出跨域请求,需要指明状态。
fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
.then(function(response) {
return response.text();
})
.then(function(text) {
console.log('Request successful', text);
})
.catch(function(error) {
log('Request failed', error)
});
除了指定模式,fetch方法的第二个参数还可以用来配置其他值,比如指定cookie连同HTTP请求一起发出。
fetch(url, {
credentials: 'include'
})
发出POST请求的写法如下。
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) {
console.log("Perfect! Your settings are saved.");
} else if (res.status == 401) {
console.log("Oops! You are not authorized.");
}
}, function(e) {
console.log("Error submitting form!");
});
目前,还有一些XMLHttpRequest
对象可以做到,但是Fetch API还没做到的地方,比如中途中断HTTP请求,以及获取HTTP请求的进度。这些不足与Fetch返回的是Promise对象有关。
Fetch API引入三个新的对象(也是构造函数):Headers
, Request
和Response
。其中,Headers
对象用来构造/读取HTTP数据包的头信息。
var content = 'Hello World';
var headers = new Headers();
headers.append("Accept", "application/json");
headers.append("Content-Type", "text/plain");
headers.append("Content-Length", content.length.toString());
headers.append("X-Custom-Header", "ProcessThisImmediately");
Headers
对象的实例,除了使用append
方法添加属性,也可以直接通过构造函数一次性生成。
reqHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
Headers对象实例还提供了一些工具方法。
reqHeaders.has("Content-Type") // true
reqHeaders.has("Set-Cookie") // false
reqHeaders.set("Content-Type", "text/html")
reqHeaders.append("X-Custom-Header", "AnotherValue")
reqHeaders.get("Content-Length") // 11
reqHeaders.getAll("X-Custom-Header") // ["ProcessThisImmediately", "AnotherValue"]
reqHeaders.delete("X-Custom-Header")
reqHeaders.getAll("X-Custom-Header") // []
生成Header实例以后,可以将它作为第二个参数,传入Request方法。
var headers = new Headers();
headers.append('Accept', 'application/json');
var request = new Request(URL, {headers: headers});
fetch(request).then(function(response) {
console.log(response.headers);
});
同样地,Headers实例可以用来构造Response方法。
var headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'max-age=3600'
});
var response = new Response(
JSON.stringify({photos: {photo: []}}),
{'status': 200, headers: headers}
);
response.json().then(function(json) {
insertPhotos(json);
});
上面代码中,构造了一个HTTP回应。目前,浏览器构造HTTP回应没有太大用处,但是随着Service Worker的部署,不久浏览器就可以向Service Worker发出HTTP回应。
Request对象用来构造HTTP请求。
var req = new Request("/index.html");
req.method // "GET"
req.url // "http://example.com/index.html"
Request对象的第二个参数,表示配置对象。
var uploadReq = new Request("/uploadImage", {
method: "POST",
headers: {
"Content-Type": "image/png",
},
body: "image data"
});
上面代码指定Request对象使用POST方法发出,并指定HTTP头信息和信息体。
下面是另一个例子。
var req = new Request(URL, {method: 'GET', cache: 'reload'});
fetch(req).then(function(response) {
return response.json();
}).then(function(json) {
someOperator(json);
});
上面代码中,指定请求方法为GET,并且要求浏览器不得缓存response。
Request对象实例有两个属性是只读的,不能手动设置。一个是referrer属性,表示请求的来源,由浏览器设置,有可能是空字符串。另一个是context属性,表示请求发出的上下文,如果是image,表示是从img标签发出,如果是worker,表示是从worker脚本发出,如果是fetch,表示是从fetch函数发出的。
Request对象实例的mode属性,用来设置是否跨域,合法的值有以下三种:same-origin、no-cors(默认值)、cors。当设置为same-origin时,只能向同域的URL发出请求,否则会报错。
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!");
});
上面代码中,如果用户输入的URL不是同域的,将会报错,否则就会发出请求。
如果mode属性为no-cors,就与默认的浏览器行为没有不同,类似script标签加载外部脚本文件、img标签加载外部图片。如果mode属性为cors,就可以向部署了CORS机制的服务器,发出跨域请求。
var u = new URLSearchParams();
u.append('method', 'flickr.interestingness.getList');
u.append('api_key', '<insert api key here>');
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);
});
});
上面代码是向Flickr API发出图片请求的例子。
Request对象的一个很有用的功能,是在其他Request实例的基础上,生成新的Request实例。
var postReq = new Request(req, {method: 'POST'});
fetch方法返回Response对象实例,它有以下属性。
status
:整数值,表示状态码(比如200)Response对象还有两个静态方法。
fetch("https://example.com", init)
.then(function (response) {
// Check that the response is a 200
if (response.status === 200) {
alert("Content type: " + response.headers.get('Content-Type'));
}
});
Request对象和Response对象都有body属性,表示请求的内容。body属性可能是以下的数据类型。
var form = new FormData(document.getElementById('login-form'));
fetch("/login", {
method: "POST",
body: form
})
上面代码中,Request对象的body属性为表单数据。
Request对象和Response对象都提供以下方法,用来读取body。
注意,上面这些方法都只能使用一次,第二次使用就会报错,也就是说,body属性只能读取一次。Request对象和Response对象都有bodyUsed属性,返回一个布尔值,表示body是否被读取过。
var res = new Response("one time use");
console.log(res.bodyUsed); // false
res.text().then(function(v) {
console.log(res.bodyUsed); // true
});
console.log(res.bodyUsed); // true
res.text().catch(function(e) {
console.log("Tried to read already consumed Response");
});
上面代码中,第二次通过text方法读取Response对象实例的body时,就会报错。
这是因为body属性是一个stream对象,数据只能单向传送一次。这样的设计是为了允许JavaScript处理视频、音频这样的大型文件。
如果希望多次使用body属性,可以使用Response对象和Request对象的clone方法。它必须在body还没有读取前调用,返回一个新的body,也就是说,需要使用几次body,就要调用几次clone方法。
addEventListener('fetch', function(evt) {
var sheep = new Response("Dolly");
console.log(sheep.bodyUsed); // false
var clone = sheep.clone();
console.log(clone.bodyUsed); // false
clone.text();
console.log(sheep.bodyUsed); // false
console.log(clone.bodyUsed); // true
evt.respondWith(cache.add(sheep.clone()).then(function(e) {
return sheep;
});
});
上篇[js点击]JavaScript之Ajax技术01