在 HTML 5 中,对 XMLHttpRequest(后续都使用 XHR 表示) 新增了关于跨域请求、进度事件的上传、二进制数据的上传及下载等许多新的功能。
html5 中新增了 Fetch API,与 XHR 的主要区别在于 Fetch API 使用了 Promise。
学习目标:
- 掌握 XHR 新增的 responseType 属性与 response 属性的概念、作用及使用方法;
- 掌握 XHR 可以发送哪些类型的数据以及如何发送这些数据;
- 掌握如何使用 XHR 跨域请求数据;
- 掌握 Fetch API 的基本概念及核心方法的使用,以及如何使用 fetch 方法向服务器端发送数据及解析响应;
从服务器端获取二进制数据
在 HTML5 之前,当使用 XHR 对象从服务器端获取二进制数据时,需要通过 XHR 对象的 overrideMimeType
方法来重载所获取数据的 Mime Type 类型,将所获取数据的字符编码(charset)修改为用户自定义类型。代码如下所示。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'test.png', true);
xhr.overrideMimeType('test/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 对象的 responseText 属性值返回的并不是原始二进制数据,而是由这些数据所组成的一串字符串。
在 HTML5 中,不推荐使用这种通过重载 MIME Type 类型来自定义数据的字符编码的方法。为了解决此类问题,HTML5 为 XHR t对象新增 responseType
属性与 response
属性。说明如下。
- responseText 属性:指定服务器端返回数据的数据类型,默认是 text。可指定属性值为 text、arraybuffer、blob、json 或 document。
- response 属性:如果发送请求成功,则 XHR 对象的 reaponse 属性值返回服务器端响应的数据。
- 当 responseType 为 text 时,response 属性值是一串字符串;
- 当 responseType 为 arraybuffer 时,response 属性值是一个 ArrayBuffer 对象;
- 当 responseType 为 blob 时,response 属性值是一个 Blob 对象;
- 当 responseType 为 json 时,response 属性值是一个 Json 对象;
- 当 responseType 为 document 时,response 属性值是一个 Document 对象。
到目前,Firefox 8以上、Opera 11.64以上、Chrome 10以上、Safari 5以上以及IE 10版本的浏览器支持 XHR 对象的 response 属性值指定为 arraybuffer 进行使用。
ArrayBuffer响应
下面是一个指定 XHR 对象的 response 属性值为 arraybuffer 的例子。示例中,当点击“下载图片”将下载一张图片,并且结合前面的本地存储知识,将下载的图片存储到 indexedDB 中;当点击“显示图片”将从 indexedDB 中取出图片显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body onload="init();">
<div>
<p>将responseType属性值指定为“arraybuffer”</p>
<input type="button" value="下载图片" onclick="downloadPic();" />
<input type="button" value="显示图片" onclick="showPic();" />
<output id="result"></output>
</div>
</body>
</html>
<script>
window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
window.IDBCursor = window.IDBCursor || window.webkitIDBCursor || window.msIDBCursor;
window.URL = window.URL || window.webkitURL;
var dbName = 'imgBD';
var dbVersion = 20150318;
var idb;
function init() {
var dbConnect = indexedDB.open(dbName, dbVersion);
dbConnect.onsuccess = function(e) {
idb = e.target.result;
console.log('数据库连接成功');
};
dbConnect.onerror = function() {
console.log('数据库连接失败');
};
dbConnect.onupgradeneeded = function(e) {
idb = e.target.result;
var tx = e.target.transaction;
tx.onabort = function(e) {
console.log('对象仓库创建失败');
}
var tableName = 'img';
var tableParams = {
keyPath: 'id',
autoIncrement: true
}
var store = idb.createObjectStore(tableName, tableParams);
console.log('对象仓库创建成功');
}
}
function downloadPic() {
var xhr = new XMLHttpRequest();
xhr.open('GET', './12.png', true);
xhr.responseText = 'arraybuffer';
xhr.onload = function(e) {
if(this.status === 200) {
var bb = new Blob([this.response]);
var reader = new FileReader();
reader.readAsDataURL(bb);
reader.onload = function() {
// 在IndexedDB数据库中保存二进制数据
var tx = idb.transaction(['img'], 'readwrite');
tx.oncomplete = function() {
console.log('数据保存成功');
}
tx.onabort = function() {
console.log('数据保存失败');
}
var store = tx.objectStore('img');
var value = {
id: 1,
img: this.result
}
store.put(value);
}
}
};
xhr.send();
}
function showPic() {
var tx = idb.transaction(['img'], 'readonly');
var store = tx.objectStore('img');
var req = store.get(1);
req.onsuccess = function() {
if(this.result == undefined) {
console.log('没有符合条件的数据');
} else {
var img = document.createElement('img');
img.src = this.result.img;
img.width = 200;
img.height = 200;
document.body.append(img);
}
}
req.onerror = function() {
console.log('获取数据失败');
}
}
</script>
Blob响应
也可以将 XHR 对象的 responseType 属性值指定为“blob”,从而将服务器端下载的二进制数据用作一个 Blob 对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body onload="init();">
<div>
<p>将responseType属性值指定为“arraybuffer”</p>
<input type="button" value="下载图片" onclick="downloadPic();" />
<input type="button" value="显示图片" onclick="showPic();" />
<output id="result"></output>
</div>
</body>
</html>
<script>
window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
window.IDBCursor = window.IDBCursor || window.webkitIDBCursor || window.msIDBCursor;
window.URL = window.URL || window.webkitURL;
var dbName = 'imgBD';
var dbVersion = 20150318;
var idb;
function init() {
var dbConnect = indexedDB.open(dbName, dbVersion);
dbConnect.onsuccess = function(e) {
idb = e.target.result;
console.log('数据库连接成功');
};
dbConnect.onerror = function() {
console.log('数据库连接失败');
};
dbConnect.onupgradeneeded = function(e) {
idb = e.target.result;
var tx = e.target.transaction;
tx.onabort = function(e) {
console.log('对象仓库创建失败');
}
var tableName = 'img';
var tableParams = {
keyPath: 'id',
autoIncrement: true
}
var store = idb.createObjectStore(tableName, tableParams);
console.log('对象仓库创建成功');
}
}
function downloadPic() {
var xhr = new XMLHttpRequest();
xhr.open('GET', './12.png', true);
xhr.responseText = 'blob';
xhr.onload = function(e) {
if(this.status === 200) {
reader.readAsDataURL(this.response);
reader.onload = function(f) {
// 在IndexedDB数据库中保存二进制数据
var tx = idb.transaction(['img'], 'readwrite');
tx.oncomplete = function() {
console.log('数据保存成功');
}
tx.onabort = function() {
console.log('数据保存失败');
}
var store = tx.objectStore('img');
var value = {
id: 1,
img: this.result
}
store.put(value);
}
}
};
xhr.send();
}
function showPic() {
var tx = idb.transaction(['img'], 'readonly');
var store = tx.objectStore('img');
var req = store.get(1);
req.onsuccess = function() {
if(this.result == undefined) {
console.log('没有符合条件的数据');
} else {
var img = document.createElement('img');
img.src = this.result.img;
img.width = 200;
img.height = 200;
document.body.append(img);
}
}
req.onerror = function() {
console.log('获取数据失败');
}
}
</script>
发送数据
html5以前,XHR 对象的 send 方法只能发送字符串或 Document 对象,而在 HTML5 中,对 XHR 对象的 send 方法进行改善,使其可以发送字符串、Document 对象、表单数据、Blob 对象、文件以及 ArrayBuffer 对象。
发送字符串
通过将 XMLHttpRequest 对象的 responseType 属性值指定为 text。