转载自:https://c.biancheng.net/view/5995.html
在 JavaScript 中,XMLHttpRequest 是客户端的一个 API,它为浏览器与服务器通信提供了一个便捷通道。现代浏览器都支持 XMLHttpRequest API,如 IE 7+、Firefox、Chrome、Safari 和 Opera。
本文实例已挂在此:demo
创建 XMLHttpRequest 对象
XMLHttpRequest 用于在后台与服务器交换数据。创建 XMLHttpRequest 对象的方法如下:
var xhr = new XMLHttpRequest ();
IE 5.0 版本开始以 ActiveX 组件形式支持 XMLHttpRequest,IE 7.0 版本开始标准化 XMLHttpRequest。不过所有浏览器实现的 XMLHttpRequest 对象都提供相同的接口和用法。
下面示例使用工厂模式把定义 XMLHttpRequest 对象进行封装,这样只需要调用 creatXHR()
方法就可以返回一个 XMLHttpRequest 对象。
//创建XMLHttpRequest 对象
//参数:无
//返回值:XMLHttpRequest 对象
function createXHR () {
var XHR = [ //兼容不同浏览器和版本得创建函数数组
function () { return new XMLHttpRequest () },
function () { return new ActiveXObject ("Msxml2.XMLHTTP") },
function () { return new ActiveXObject ("Msxml3.XMLHTTP") },
function () { return new ActiveXObject ("Microsoft.XMLHTTP") }
];
var xhr = null;
//尝试调用函数,如果成功则返回XMLHttpRequest对象,否则继续尝试
for (var i = 0; i < XHR.length; i ++) {
try {
xhr = XHR[i]();
} catch(e) {
continue //如果发生异常,则继续下一个函数调用
}
break; //如果成功,则中止循环
}
return xhr; //返回对象实例
}
在上面代码中,首先定义一个数组,收集各种创建 XMLHttpRequest 对象的函数。第 1 个函数是标准用法,其他函数主要针对 IE 浏览器的不同版本尝试创建 ActiveX 对象。然后设置变量 xhr 为 null,表示为空对象。接着遍历工厂内所有函数并尝试执行它们,为了避免发生异常,把所有调用函数放在 try 中执行,如果发生错误,则在 catch 中捕获异常并执行 continue 命令,返回继续执行,避免抛出异常。如果创建成功,则中止循环,返回 XMLHttpRequest 对象。
建立连接
在 JavaScript 中,使用 XMLHttpRequest 对象的 open()
方法可以建立一个 HTTP 请求。用法如下:
xhr.open(method, url, async, username, password);
其中 xhr 表示 XMLHttpRequest 对象,open()
方法包含 5 个参数,说明如下:
- method:HTTP 请求方法,必须参数,值包括 POST、GET 和 HEAD,大小写不敏感。
- url:请求的 URL 字符串,必须参数,大部分浏览器仅支持同源请求。
- async:指定请求是否为异步方式,默认为 true。如果为 false,当状态改变时会立即调用 onreadystatechange 属性指定的回调函数。
- username:可选参数,如果服务器需要验证,该参数指定用户名,如果未指定,当服务器需要验证时,会弹出验证窗口。
- password:可选参数,验证信息中的密码部分,如果用户名为空,则该值将被忽略。
发送请求
建立连接后,可以使用 send()
方法发送请求。用法如下:
xhr.send(body);
参数 body 表示将通过该请求发送的数据,如果不传递信息,可以设置为 null 或者省略。
发送请求后,可以使用 XMLHttpRequest 对象的 responseBody、responseStream、responseText 或 responseXML 属等待接收响应数据。
示例
下面示例简单演示了如何实现异步通信的方法。
<script>
var xhr = createXHR(); //实例化 XMLHttpRequest 对象
xhr.open("GET", "server.txt", false); // 建立连接
xhr.send(); //发送请求
document.write(xhr.responseText); //打印接收数据
</script>
在服务器端(server.txt)中输入字符串"Hello World"。在浏览器中浏览时会弹出对话框显示“Hello World”的提示信息。该字符串是从服务器端 server.txt 所响应的字符串。
发送 GET 请求
在 JavaScript 中,发送 GET 请求简单、方便,适用于简单字符串,不适用于大容量或加密数据。
实现方法:将包含查询字符串的 URL 传入 open()
方法,设置第 1 个参数值为 GET ,服务器即可通过查询字符串接收用户信息(如上面的实例代码)。
示例
下面示例以 GET 方式向服务器传递一条信息 callback=GET数据。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var url = "server.php?callback=GET数据"; //设置查询字符串
var xhr = createXHR(); //实例化XMLHttpRequest 对象
xhr.open("GET", url, false); //建立连接,要求同步响应
xhr.send(null); //发送请求
var o = document.getElementById("grid");
o.innerHTML = xhr.responseText; //输出接收数据
}
}
</script>
<div id="grid"></div>
在服务器端文件(server.php)中输入下面的代码,获取查询字符串中 callback 的参数值,并把该值响应给客户端。
<?php
echo $_GET["callback"];
?>
在浏览器中预览页面,当单击提交按钮时,在控制台显示传递的参数值。
查询字符串通过问号 ? 作为前缀附加在 URL 的末尾,发送数据是以连字符 & 连接的一个或多个名值对。
发送 POST 请求
在 JavaScript 中,POST 请求允许发送任意类型、长度的数据,多用于表单提交,以 send()
方法进行传递,而不以查询字符串的方式进行传递。POST 字符串与 GET 字符串的格式相同。格式如下:
send("name1=value1&name2=value2...");
示例
使用 POST 方法向服务器传递数据。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var url = "server.php"; //设置请求的地址
var xhr = createXHR(); //实例化 XMLHttpRequest 对象
xhr.open("POST", url, false); //建立连接,要求同步响应
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //设置为表单方式提交
xhr.send("callback=POST数据"); //发送请求
var o = document.getElementById("grid");
o.innerHTML = xhr.responseText; //输出接收数据
}
}
</script>
<div id="grid"></div>
在 open()
方法中,设置第一个参数为 POST,然后使用 setRequestHeader()
方法设置请求消息的内容类型为“application/x-www-form-urlencoded”,它表示传递的是表单值,一般使用 POST 发送请求时都必须设置该选项,否则服务器无法识别传递过来的数据。
在服务器端设计接收 POST 方式传递的数据,并进行响应。
<?php
echo $_POST["callback"];
?>
串行格式化数据
GET 和 POST 方法都是以名值对的字符串格式发送数据的。
1)对象信息
下面是一个包含 3 个名值对的 JSON 类型数据。
{ user : "css8", pass : "123456", email : "css8@123.cn" }
将 JSON 数据转换为串行格式化显示如下。
'user="css8" & pass="123456" & email="css8@123.cn"'
2)数组信息
下面是一组有序的 JSON 信息,包含多个值。(转载的原文这里有坑)
[{name : "user", value : "css8"} , {name : "pass", value : "123456"}, {name : "email", value : "css8@123.cn"}]
将上面数据转换为串行格式显示如下。
'user="css8" & pass="123456" & email="css8@123.cn"'
示例
为了方便开发,可以定义一个工具函数,该函数能够把数据转换为串行格式化字符串并返回。
//把JSON数据转换为串行字符串
//参数:data表示数组或对象类型的数据
//返回值:串行字符串
function JSONtoString(data) {
var a = []; //临时数组
if (data.constructor == Array) { //处理数组
for (var i = 0; i < data.length; i++) {
a.push(data[i].name + "=" + encodeURIComponent(data[i].value));
}
} else { //处理对象
for (var i in data) {
a.push(i + "=" + encodeURIComponent(data[i]));
}
}
return a.join("&"); //把数组转换为串行字符串,并返回
}
var json = [
{ name: "user", value: "ymz" },
{ name: "passwd", value: "123456" },
{ name: "email", value: "ymz@126.com" }
]
//通过转换函数转换 JSON 数据
document.write("这是将json数据转换后的字符串:" + JSONtoString(json));
异步响应状态
在 JavaScript 中,可以通过 readyState 属性来实时跟踪异步响应的状态。
当该属性值发生变化时,会触发 readystatechange 事件,并调用绑定的回调函数。
readyState 属性值:
返回值 | 说明 |
---|---|
0 | 未初始化。表示对象已经建立,但是尚未初始化,尚未调用 open() 方法 |
1 | 初始化。表示对象已经建立,尚未调用 send() 方法 |
2 | 发送数据。表示 send() 方法已经调用,但是当前的状态及 HTTP 头未知 |
3 | 数据传送中。已经接收部分数据,因为响应及 HTTP 头不安全,这时通过 responseBody 和 responseText 获取部分数据会出现错误 |
4 | 完成。数据接收完毕,此时可以通过 responseBody 和 responseText 获取完整的响应数据 |
如果 readyState 属性值为 4,则说明响应完毕,那么就可以安全的读取响应的数据。
考虑到各种特殊情况,更安全的方法是同时监测 HTTP 状态码,只有当 HTTP 状态码为 200 时,才说明 HTTP 响应顺利完成。
示例
下面示例中,修改请求为异步响应请求,然后通过 status 属性获取当前的 HTTP 状态码。如果 readyState 属性值为 4,且 status(状态码)属性值为 200,则说明 HTTP 请求和响应过程顺利完成,这时可以安全、异步的读取数据。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var url = "server.php"; //设置请求的地址
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("POST", url, true); //建立间接,要求异步响应
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); //设置为表单方式提交
xhr.onreadystatechange = function () { //异步响应需绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
var o = document.getElementById("grid");
o.innerHTML = xhr.responseText; //输出接收数据
}
}
}
xhr.send("callback=POST数据"); //发送请求
}
}
</script>
<div id="grid"></div>
中止异步响应请求
使用 abort() 方法可以中止正在进行的异步响应请求。用法如下:
xhr.onreadystatechange = function () {}; //清理事件响应函数
xhr.abort(); //中止请求
在调用 abort()
方法前,应先清除 onreadystatechange 事件处理函数:因为 IE 和 Mozilla 在请求中止后也会激活这个事件处理函数。如果给 onreadystatechange 属性设置为 null,则 IE 会发生异常,所以为它设置一个空函数。
获取 XML 数据
XMLHttpRequest 对象通过 responseText、responseBody、responseStream 或 responseXML 属性获取响应信息,说明如下表所示,它们都是只读属性。
|XMLHttpRequest 对象响应信息属性:
响应信息 | 说明 |
---|---|
responseBody | 将响应信息正文以 Unsigned Byte 数组形式返回 |
responseStream | 将响应信息以 ADO Stream 对象的形式返回 |
responseText | 将响应信息作为字符串返回 |
responseXML | 将响应信息格式化为 XML 文档格式返回 |
在实际应用中,一般将格式设置为 XML、HTML、JSON 或其他纯文本格式。具体使用哪种响应格式,可以参考下面几条原则。
- 如果向页面中添加大块数据,选择 HTML 格式会比较方便。
- 如果需要协作开发,且项目庞杂,选择 XML 格式会更通用。
- 如果要检索复杂的数据,且结构复杂,那么选择 JSON 格式更加轻便。
示例1
在服务器端创建一个简单的 XML 文档 server.xml。
<?xml version="1.0" encoding="utf-8"?>
<the>XML 数据</the>
然后,在客户端进行如下请求。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("GET", "server.xml", true); //建立连接,要求异步响应
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码!引用的原文这里有坑
var info = xhr.responseXML;
var o = document.getElementById("grid");
o.innerHTML = info.getElementsByTagName("the")[0].firstChild.data; //输出元信息字符串“XML 数据”
}
}
}
xhr.send(); //发送请求
}
}
</script>
<div id="grid"></div>
在上面代码中,使用 XML DOM 的 getElementsByTagName()
方法获取 the 节点,然后再定位第一个 the 节点的子节点内容。此时如果继续使用 responseText 属性来读取数据,则会返回 XML 源代码字符串。
示例2
以示例 1 为例,使用服务器端脚本生成 XML 结构数据。
<?php
header('Content-Type: text/html;');
echo '<?xml version="1.0" encoding="utf-8"?><the>XML 数据</the>'; //输出XML
?>
获取 HTML 字符串
设计响应信息为 HTML 字符串,然后使用 innerHTML 把获取的字符串插入到网页中。
示例
在服务器端 server.html 文件设计响应信息为 HTML 结构代码。
<table border="1" width="100%">
<tr><td>RegExp.exec()</td><td>通用的匹配模式</td></tr>
<tr><td>RegExp.test()</td><td>检测一个字符串是否匹配某个模式</td></tr>
</table>
然后在客户端可以这样接收响应信息。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("GET", "server.html", true); //建立连接,要求异步响应
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
var o = document.getElementById("grid");
o.innerHTML = xhr.responseText; //直接插入到页面中,并会解析插入的html代码
}
}
}
xhr.send(); //发送请求
}
}
</script>
<div id="grid"></div>
在某些情况下,HTML 字符串可能为客户端解析响应信息节省了一些 JavaScript 脚本,但是也带来了一些问题。
- 响应信息中包含大量无用的字符,响应数据会变得很臃肿。因为 HTML 标记不含有信息,完全可以把它们放置在客户端,由 JavaScript 脚本负责生成。
- 响应信息中包含的 HTML 结构无法有效利用,对于 JavaScript 脚本来说,它们仅仅是一堆字符串。同时结构和信息混合在一起,也不符合标准化设计原则。
获取 JavaScript 脚本
设计响应为 JavaScript 代码,与 JSON 数据不同,它是可执行的命令或脚本。
示例
在服务器端请求文件 server.js 中包含下面一个函数。
function () {
var d = new Date();
return d.toString();
}
然后在客户端执行下面的请求。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("GET", "server.js", true); //建立连接,要求异步响应
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
var info = xhr.responseText;
var o = document.getElementById("grid");
o.innerHTML = eval("(" + info + ")()"); //eval((js脚本字符串)())把脚本字符串转换为执行脚本
}
}
}
xhr.send(); //发送请求
}
}
</script>
<div id="grid"></div>
使用 eval()
方法时,在字符串前后附加两个小括号:一个是包含函数结构体的,一个是表示调用函数的。不建议直接使用 JavaScript 代码作为响应格式,因为它不能传递更丰富的信息,同时 JavaScript 脚本极易引发安全隐患。
获取 JSON 数据
使用 responseText 可以获取 JSON 格式的字符串,然后使用 eval() 方法将其解析为本地 JavaScript 脚本,再从该数据对象中读取信息。
示例
在服务器端请求文件 server.json 中包含下面 JSON 数据。
{ user : "css8", pass : "123456", email : "css8@123.cn" }
然后在客户端执行下面的请求。把返回 JSON 字符串转换为对象,然后读取属性值。
纯文本复制
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("GET", "server.json", true); //建立连接,要求异步响应
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
var info = xhr.responseText;
var jsonstr = eval("(" + info + ")"); //调用eval()把字符串转换为本地脚本
var o = document.getElementById("grid");
o.innerHTML = info + "<br>" +jsonstr.email; //输出json文件内容以及转换后的JSON对象的email属性值
}
}
}
xhr.send(); //发送请求
}
}
</script>
<div id="grid"></div>
eval() 方法在解析 JSON 字符串时存在安全隐患。如果 JSON 字符串中包含恶意代码,在调用回调函数时可能会被执行。解决方法:先对 JSON 字符串进行过滤,屏蔽掉敏感或恶意代码。当然,如果你确信所响应的 JSON 字符串是安全的,没有被人恶意攻击,那么可以使用 eval() 方法解析 JSON 字符串。
获取纯文本
对于简短的信息,可以使用纯文本格式进行响应。但是纯文本信息在传递过程中容易丢失,且没有办法检测信息的完整性。
示例
服务器端响应信息为字符串“hello”,则可以在客户端这样设计。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("GET", "server.txt", true); //建立连接,要求异步响应
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
var info = xhr.responseText;
var o = document.getElementById("grid");
if (info == "hello") document.getElementById("grid").innerHTML = "文本信息传输完整,为:" + xhr.responseText; //检测信息是否完整
else document.getElementById("grid").innerHTML = "文本信息传输可能存在丢失";
}
}
}
xhr.send(); //发送请求
}
}
</script>
<div id="grid"></div>
获取和设置头部消息
HTTP 请求和响应都包含一组头部消息,获取和设置头部消息可以使用下面两个方法。
- getAllResponseHeaders():获取响应的 HTTP头部消息。
- getResponseHeader("Header-name"):获取指定的 HTTP 头部消息。
示例
下面示例将获取 HTTP 响应的所有头部消息。
<input name="submit" type="button" id="submit" value="向服务器发出请求" />
<script>
window.onload = function () { //页面初始化
var b = document.getElementById("submit");
b.onclick = function () {
var xhr = createXHR(); //实例化XMLHttpRequest对象
xhr.open("GET", "server.txt", true); //建立连接,要求异步响应
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
var o = document.getElementById("grid");
o.innerHTML = xhr.getAllResponseHeaders();
}
}
}
xhr.send(); //发送请求
}
}
</script>
<div id="grid"></div>
如果要获取指定的某个头部消息,可以使用 getResponseHeader()
方法,参数为获取头部的名称。例如,获取 Content-Type 头部的值,可以这样设计。
console.log(xhr.getResponseHeader("Content-Type"));
除了可以获取这些头部消息外,还可以使用 setResponseHeader()
方法在发送请求中设置各种头部消息。用法如下:
xhr.setResponseHeader("Header-name", "value");
其中 Header-name 表示头部消息的名称,value 表示消息的具体值。例如,使用 POST 方法传递表单数据,可以设置如下头部消息。
xhr.setResponseHeader("Content-Type", "application/x-www-form-urlencoded");