XHR与跨域问题

XMLHttpRequest

XMLHttpRequest 对象用于在后台与服务器交换数据。XMLHttpRequest是Ajax开发中的核心对象,Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。

  • 在不重新加载页面的情况下更新网页
  • 在页面已加载后从服务器请求数据
  • 在页面已加载后从服务器接收数据
  • 在后台向服务器发送数据

XMLHttpRequest 详解

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function ajax(url,postData,fnSuc){
var xhr;
if(window.XMLHttpRequest){
xhr= new XMLHttpRequest();
//console.log(xhr);
}else{
// alert("不存在");
xhr= new ActiveXObject("Microsoft.XMLHTTP");
//alert(xhr);
}//XMLHttpRequest兼容性处理
xhr.open("POST", url , true);//指定请求的方式post/get,url,true/false(异步/同步)
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.onreadystatechange = function(){//请求状态改变时触发
var XMLHttpReq = xhr;
if (XMLHttpReq.readyState == 4) {//数据接受完成
if (XMLHttpReq.status == 200) {//服务器返回的http状态码,200表示成功
var text = XMLHttpReq.responseText;//服务器响应的文本内容
fnSuc(JSON.parse(text));//请求成功时返回的数据
}
}
};
postData = (function(obj){ // 转成post需要的字符串
var str = "";
for(var prop in obj){
str += prop + "=" + obj[prop] + "&"
}
return str;
})(postData);
xhr.send(postData);//向服务器发送请求
}

方法

1. 创建 XMLHttpRequest 对象

1
2
3
xmlhttp=new XMLHttpRequest();
//老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 对象:
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

下面是建立XHR对象的常用方法:

1
2
3
4
5
6
7
8
9
xhr=null;
if (window.XMLHttpRequest)
{// code for all new browsers
xhr=new XMLHttpRequest();
}
else if (window.ActiveXObject)
{// code for IE5 and IE6
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}

2. open:创建请求

1
xhr.open('请求方式','请求url',是异步|同步)

我们通过XMLHttpRequest对象的open函数打开对服务器的连接,设置请求方式如GET POST OPTION DELETE等,请求路径,同步请求或者是异步请求(true表示异步请求,false表示同步请求)

3. setRequestHeader:更改请求包头

1
2
3
4
5
6
var client = new XMLHttpRequest();
client.open('GET', 'demo.cgi');
client.setRequestHeader('X-Test', 'one');
client.setRequestHeader('X-Test', 'two');
// 最终request header中"X-Test"为: one, two
client.send();

setRequestHeader必须在open()方法之后,send()方法之前调用,否则会抛错;该函数可以调用多次,且采用追加的方式。

4. send(null/参数):发出请求

发送请求,不传值时可以写null,get或者post请求传值时可以写键值对 username=zhangsan&pwd=12345

POST请求时,一定要注意要设置 Content-Type: application/x-www-form-urlencoded 不然无法解析&分隔符。

5. getAllResponseHeaders():获取响应头信息

6. getResponseHeader(String header):获取指定响应头信息

7. Abort():停止当前http请求

属性

1. readyState:XMLHttpRequest对象的状态

如果需要接收的是异步响应,这就需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。这个属性可取的值如下:

0(UNSENT):未初始化。尚未调用open()方法
1(OPENED):启动。已经调用open()方法,但尚未调用send()方法
2(HEADERS_RECEIVED):发送。己经调用send()方法,且接收到头信息
3(LOADING):接收。已经接收到部分响应主体信息
4(DONE):完成。已经接收到全部响应数据,而且已经可以在客户端使用了

理论上,只要readyState属性值由一个值变成另一个值,都会触发一次readystatechange事件。可以利用这个事件来检测每次状态变化后readyState的值。通常,我们对readyState值为4的阶段感兴趣,因为这时所有数据都已就绪

2. Onreadystatechange:状态改变事件触发器

当 XMLHttpRequest 对象的状态发生改变时,会触发此函数。状态从 0 (uninitialized) 到 4 (complete) 进行变化。(readyState变化时会调用这个属性上注册的javascript函数)

3. responseText

服务器响应的文本内容

4. responseXML

服务器响应的XML内容对应的DOM对象

5. status

服务器返回的http状态码。200表示“成功”,404表示“未找到”,500表示“服务器内部错误”等。

6. statusText

服务器返回状态的文本信息。

跨域方式

CORS(跨域资源共享)

为了实现不同网站之间的通信,浏览器实现了一种共享资源的方式。
例如a.com要获取b.com的内容,那么就要在a.com的页面中设置CORS头部

1
2
header('Access-Control-Allow-Origin:http://b.com');
header('Access-Control-Allow_Origin:*');

window.name

iframe和window.name结合可以实现跨域传输,即使父窗口和子窗口的源不同,也可以获取window.name的值

1
2
3
4
5
6
7
8
9
<script>
function getData(){
var iframe = document.getElementById('ifr');
iframe.onload = function(){
var data = iframe.contentWindow.name;
}
iframe.src = 'b.html';
}
</script>

Jsonp

1
2
3
4
5
6
7
8
9
<script>
function _callback(s){
alert(JSON.stringify(s));
}
</script>
<script src="http://example.com/json.php?cb=_callback"></script>
http://example.com/json.php?cb=_callback的响应结果类似:

__Jquery({"id":1,"content":"hello"})

原理是script标签可以跨域请求(类似的还有img等),这里jsonp请求获取到的是一串js代码,一般是一个函数调用,参数就是想要跨域获取的数据,而函数的实现在发起请求的页面中。
获取完毕后,调用该函数,即可获取数据并进行后续处理。