目录
AJAX 是 Asynchronous JavaScript + XML 的简称 。AJAX 一词的实际含义为“不发生页面跳转、异 步载入内容并改写页面内容的技术”。在实际操作中,AJAX 不仅仅会使用XML 数据,很多时候也会对 JSON 或纯文本进行操作。AJAX 的关键在于它是以异步的方式执行的。异步处理的优点是不会让用户白白等待。对于同步处 理来说,在处理完来自服务器的响应之前,用户无法进行任何其他操作,只能等待。如果服务器的响应 发生了延迟,会让用户误以为页面失去了响应。在优先考虑用户体验时,与同步处理相比,采用异步处 理的方式更为合适,这一点是显而易见的。
1. XMLHttpRequest
通过使用XMLHttpRequest 对象令JavaScript 动态地向服务器发送请求。
XMLHttpRequest 的跨浏览器支持
if (!window.XMLHttpRequest) {
// Internet Explorer 6
XMLHttpRequest = function () {
var objs = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
for (var i = 0; i < objs.length; i++) {
var obj = objs[i];
try {
return new ActiveXObject(obj);
} catch (ignore) {
}
}
throw new Error('Cannot create XMLHttpRequest object.');
}
}
var xhr = new XMLHttpRequest();
2. 使用 XMLHttpRequest 时的基本处理流程
对服务器的 URL 进行指定,以发送请求。
发送请求
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert(xhr.responseText);
}
}
};
xhr.open('GET', 'http://example.com/something');
xhr.setRequestHeader('If-Modiified-Since', 'Thu 01 Jun 1970 00:00:00 GMT');
xhr.send(null);
onreadystatechange 这一事件处理程序将会在XMLHttpRequest 对象的状态发生变化时被调用。
readyState | 含义 |
---|---|
0 | open() 尚未被调用 |
1 | send() 尚未被调用 |
2 | 服务器尚未返回响应 |
3 | 正在接收来自服务器的响应 |
4 | 完成了对来自服务器的响应的接收 |
在 status 中包含了响应的状态码。如果通信正常结束,该值为200。
传递给 open() 的参数是 HTTP 请求类型及通信目标服务器的 URL。如果传递了 false 值至第 3 个参数,XMLHttpRequest 就会执行同步通信。该参数的默认值为 true,也 就是将执行异步通信。第 4 个参数与第5 个参数分别是用户ID 和密码。在向需要进行 身份认证的服务器发送请求时要用到这两个参数。
setRequestHeader() 用于请求头部的设置。在通信的目标服务器中会自动发送对应的Cookie, 所以并不需要显式地设置。
实际向服务器发送请求的是send()。如果是POST 请求类型,则会将参数所收到的数据发送至服务 器。如果是 GET 请求类型或 HEAD 请求类型等不需要发送数据的 HTTP 请求类型,则参数为 null。
3. 通过XMLHttpRequest 进行同步通信
如果要执行同步通信,则不必 对 onreadystatechange 事件处理程序进行设定。在执行了send() 之后该处理将会进入待机状态,只要在 send() 之后继续书写对响应的处理操作即可。
通过 XMLHttpRequest 进行同步通信
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/something', false);
// 将第 3 个参数指定为 false 的话就会执行同步通信
xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); xhr.send(null); // 此时,客户端侧的处理将会进入待机状态
// 执行至此时已经完成了对响应的接收
if (xhr.status === 200) {
alert(xhr.responseText);
}
4. 超时处理
如果要取消请求,其实只需要执行abort() 方法即可。而通过setTimeout() 方法可以在一定时间后执 行 abort() 方法,从而实现超时功能。另外还有一个 clearTimeout()方法,如果在一定时间内收到了返回的 响应,该方法就将会取消 abort() 的执行。
var xhr = new XMLHttpRequest();
var timerId = window.setTimeout(function() {
xhr.abort();
}, 5000); // 5 秒后将会超时
xhr.onreadystatechange = function() {
if (request.readyState === 4) {
// 取消超时处理
window.clearTimeout(timeId);
}
};
5. 响应
通用类型的响应 :可以通过responseText 属性来引用一个XMLHttpRequest 响应。
XML 类型的响应 :以XML 的形式接收XMLHttpRequest 的响应。
JSON 形式的响应 :返回JSON 的 API。
//通用类型的响应
var xhr = XMLHttpRequest();
// ...
var dom = document.getElementById('foo');
foo.innerHTML = xhr.responseText;
//XML 类型的响应
var xhr = XMLHttpRequest();
// ...
var xml = xhr.responseXML;
// 假定 xml 的内部是这样的内容
// <result>
// <apiversion>1.0</apiversion>
// <value>foo</value>
//</result>
alert(xml.getElementsByTagName('value')[0].firstChild.nodeValue); // => foo
//JSON 类型的响应
var xhr = XMLHttpRequest();
// ...
var json = JSON.parse(xhr.responseText);
// 假定 json 的内部是这样的内容
// {
// "apiversion": 1.0,
// "value": "foo"
// }
alert(json.value); // => foo
6. 跨源限制
跨源限制指的是,对源不同的通信进行限制。而这里的源指的是由URL 的协议(http: 或 https: 等)、主机名、端口号所构成的元素。在Web 领域,为了确保安全性,只有同源的通信才能被允许进行, 这称为同源策略。
对于XMLHttpRequest 来说,同源策略的含义是,一个XMLHttpRequest 对象只能发送至一个特定的 服务器,即提供了使用该XMLHttpRequest 对象的文档的下载的那个服务器。不过,只要让服务器转发 该请求,就能够将请求发送至不同域的服务器。
7. 跨源通信
可以通过服务器转发或Flash 来实现跨源请求的发 送,也可以通过 JavaScript 实现跨源通信。
JSONP
JSONP 是 JSON with Padding 的简称。这里的 Padding 指的是向 JSON 数据中添加函数名。JSONP 是无法在POST 请求类型中使用。
JSONP 的使用示例
<script>
function foo(json) {
// 使用 json 数据进行一些操作
}
function loadData() {
var elem = document.createElement('script');
// 将 foo 指定为所要执行的回调函数
// 在使用 JSONP 的 API 中,常常可以对 callback 函数的名称进行指定
elem.src = 'http://api.example.com/some-data&callback=foo';
// 将 script 标签添加至 head 中
// 这时 DOM 将被重建,并载入 script 标签的 src 的内容
// 载入之后就会执行 foo 函数
document.getElementByTagName('head')[0].append(elem);
}
</script>
iframe 攻击(iframe hack)
API 请求
首先,在my.example.com 的页面中将会指定一个other.example.com 中的html 来创建一个iframe。这里 的关键点在于 URL 中包含了哈希片段。哈希片段被指定为了进行 API 调用时所需的数据。
响应
在 other.example.com 的页面中,将会通过使用XMLHttpRequest 之类的方式调用other.example. com 中的功能并获取数据。这时还没有进行跨源的功能调用,必须在取得数据后再将它们传回之前 的 my.example.com 中的页面。为此,需要在other.example.com 的页面内创建一个iframe,并将其指向 my.example.com 中的页面。即孙iframe。这一孙iframe 的 URL 也要被指定为哈希片段。和在父页面中创 建的指向 other.example.com的子 iframe一样,数据将被置于哈希片段之中。
回调函数
由于孙iframe 与父页面都是my.example.com 中的页面,因此可以在孙iframe 中执行父页面中的函 数。这时,孙iframe 的 onload 将会调用父页面的函数,从而实现callback 的调用。当然了,在调用函数 时所使用的参数是从子iframe 传来的location.hash 的值。至于子iframe 将会调用哪一个页面,则是在创 建子iframe 时通过哈希片段来指定的。只要在创建时将所指定的这一页面置于子iframe 内即可。如此一 来,从父页面的角度来看,就实现了与跨源通信相同的执行结果。
通过 iframe 实现跨源通信(父页面)
<html>
<head>
<title> 父页面 </title>
<script>
// 在跨源通信中用于获取数据的函数
function getData() {
// 此处子 iframe 的 URL 为 other.example.com 的页面
// 参数则是在 # 之后的数据
frames[0].location.href =
'http://other.example.com/api.html#' +
'{' +
// 这里是事实上希望执行的 API
'"api": "http://other.example.com/some-data",' +
// 在子 iframe 中指定的孙 iframe 的 URL
'"callback": "http://my.example.com/callback.html"' +
'}';
}
// 在跨源通信中作为回调函数被执行的函数
// 由孙 iframe 调用
function callback(param) {
document.getElementById("result").innerHTML = param;
frames[0].frames[0].location.href = 'dummy.gif';
}
</script>
</head>
<body>
<input type="button" value=“从 other.example.com 获取数据” οnclick="getData()">
<div id="result"></div>
<iframe id="child-frame" src="dummy.gif" style="display: none;"></iframe>
</body>
</html>
通过 iframe 实现跨源通信(子 iframe)
<html>
<head>
<title> 子 iframe</title>
<script>
function executeApi() {
// 将 location.hash 的第一个字符 (#) 去除,将剩余部分以 JSON 格式进行分析
var param = JSON.parse(location.hash.substring(1));
var xhr = new XHMHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var iframe = document.getElementById('grandchild-iframe');
iframe.location.href = param.callback + '#' + xhr.responseText;
}
};
xhr.open(param.api, 'GET');
xhr.send(null);
}
</script>
</head>
<body οnlοad='executeApi()'>
<iframe id="grandchild-iframe" src="dummy.gif" style="display: none;"></iframe>
</body>
</html>
通过 iframe 实现跨源通信(孙 iframe)
<html>
<head>
<title> 孙 iframe</title>
<script>
window.onload = function() {
window.top.callback(location.hash);
}
</script>
</head>
<body></body>
</html>
window.postMessage
通过 postMessage 实现跨源通信(父页面)
<html>
<head>
<title> 父页面 </title>
<script>
// 在跨源通信中用于获取数据的函数
function getData() {
// 对子 iframe 进行 postMessage 操作
frames[0].postMessage('http://other.example.com/some-data','http://other.example.com');
}
// 在跨源通信中作为回调函数被执行的函数
// 被设定为用于接收来自子 iframe 的消息
window.addEventListener('message', function(event) {
if (event.origin !== 'http://other.example.com') {
return;
}
// 将结果保存于 event.data 中
document.getElementById("result").innerHTML = event.data;
}, false);
</script>
</head>
<body>
<input type="button" value=“从 other.example.com 获取数据” οnclick="getData()">
<div id="result"></div>
// 将 other.example.com 的页面指定为子 iframe 的 URL
<iframe id="child-frame" src="http://other.example.com/api.html" style="display: none;"></iframe>
</body>
</html>
通过 postMessage 实现跨源通信(子 iframe)
<html>
<head>
<title> 子 iframe</title>
<script>
window.addEventListener('message', function(event) {
if (event.origin !== 'my.example.com') {
return;
}
var xhr = new XHMHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
// 将 responseText 作为消息返回
event.source.postMessage(xhr.responseText, 'http://my.example.com');
}
};
var url = event.data;
xhr.open(url, 'GET');
xhr.send(null); }, false);
</script>
</head>
<body></body>
</html>
XMLHttpRequest Level 2
XMLHttpRequest Level 2
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://other.example.com', true);
xhr.withCredentials = true; // 设定为将会发送 Cookie
xhr.onreadystatechange = function() {
// 进行一些操作
};
xhr.send();
来源:CSDN
作者:青花和韵
链接:https://blog.csdn.net/weixin_43307431/article/details/104693844