XHR对象:

什么是 XMLHttpRequest 对象?
XMLHttpRequest 对象用于在后台与服务器交换数据。XMLHttpRequest 是 AJAX 的基础。
XMLHttpRequest 对象是 W3C 的标准吗?
任何 W3C 推荐标准均未规定 XMLHttpRequest 对象。
AJAX请求和浏览器请求的区别?
本质上,不管是Ajax还是浏览器请求,都是一次基于HTTP的一问一答过程。
功能上,浏览器请求(js,css,图片,form表单提交)和Ajax请求都携带Cookie信息。但浏览器规定,静态资源请求和提交表单不受同源政策的限制,Ajax请求受同源策略限制。
怎么区分ajax请求和浏览器请求?
可以通过Request.IsAjaxRequest方法判断是否是ajax过来的请求,ajax发起的请求多一个协议头X-Requested-With:XMLHttpRequest。

XHR发送请求和接收响应:

如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:

// open方法规定请求的类型、URL 以及是否异步处理请求。
// send方法将请求发送到服务器。data仅用于 POST 请求。
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://www.baidu.com?t='+Math.random(), true) 
xhr.setRequestHeader("Content-type","xxx") // 添加 HTTP 头
xhr.send(data)

如需获得来自服务器的响应,我们使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。如果来自服务器的响应并非 XML,请使用 responseText 属性。

readyState属性存有XMLHttpRequest对象的状态。从 0(请求未初始化) 到 4(请求已完成,且响应已就绪) 发生变化。
status属性存有HTTP响应状态码,从1xx(hold on)到5xx(I fucked off)。
每当 readyState 改变时,就会触发 onreadystatechange 事件。
onreadystatechange 事件被触发 4 次(0 - 4), 分别是: 0-1、1-2、2-3、3-4。

当readyState等于4且状态码为200 时,表示响应已就绪:
xhr.onreadystatechange = function()  {  
  if (xhr.readyState ==4 && xhr.status==200)  {
   console.log(xhr.responseText) 
  }  
}

最简单的解决跨域方法是JSONP:
JSONP:只支持GET,不支持POST请求代理。由于JSONP是最灵活,也是最常用的方式
原理:浏览器只对XHR(XMLHttpRequest)请求有同源请求限制,而对script标签src属性、link标签ref属性和img标签src属性没有这这种限制,利用这个“漏洞”就可以很好的解决跨域请求。JSONP就是利用了script标签无同源限制的特点来实现的,当向第三方站点请求时,我们可以将此请求放在<script>标签的src属性里,这就如同我们请求一个普通的JS脚本,可以自由的向不同的站点请求:

<script type="text/javascript" src='http://www.baidu.com/?callback=hello'>
  function hello(res) {
    console.log(res);
  }
</script>

上面代码执行后报如下错误:
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://www.baidu.com/?callba... with MIME type text/html

为什么浏览器要限制跨域访问?

浏览器一直在做的假设是,任何时候只要用户开始使用互联网应用,这个应用就开始尝试攻击这个用户,也就是说互联网应用是默认不可信的。
最早迫使浏览器采用不信任互联网应用这个设计思想的攻击方式,就是跨站点脚本攻击。
跨站脚本攻击XSS(Cross Site Scripting)常见方式:
1、通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行恶意代码。例如,当动态页面中插入的内容含有这些特殊字符(如<)时,用户浏览器会将其误认为是插入了HTML标签,当这些HTML标签引入了一段JavaScript脚本时,这些脚本程序就将会在用户浏览器中执行。
2、用户点击不明链接进入攻击网站,攻击网站执行JavaScript脚本,访问用户设备上的数据,发送到攻击者服务器上。跨站脚本攻击可能有很多变种,这里说的是最一般的思路。

同源政策隔断跨站资源共享,降低攻击:
同源政策(Same Origin Policy, SOP)说的就是,来自某一个服务器「源」的数据,以及来自这个服务器的程序的数据,都与来自任何其他源的任何数据分开。
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。--百科
同源策略会阻断数据融合,举个例子,当政府开始公开大量的开放公共数据时,一些网站从许多不同的开放数据站点加载数据并提供数据的「融合」—— 组合许多不同来源的数据,并提供可视化,从而让用户享受到单一数据源所不能提供的洞察力。

跨域资源共享CORS(Cross-Origin Resource Sharing)提供安全跨站资源共享,实现数据融合:
CORS是一个W3C标准,它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
也就是说,实现CORS通信的关键是改变开放数据发布者,浏览器制造商要求开放数据发布者在 HTTP 响应中为开放的数据添加特殊的 CORS 头:

1、源控制(必需)
Access-control-allow-Origin: * // 对任意源开放
Access-control-allow-Origin: http://www.xx // 对指定源开放
2、方法控制(非简单请求必需)
Access-Control-Allow-Methods: GET, POST, PUT // 表明服务器支持的所有跨域请求的方法
2、响应头拦截(请求头有Access-Control-Request-Headers时必需)
除了阻止访问数据以外,CORS 系统还会阻止不同源的服务器的响应头发送给互联网应用。如果不想被阻止,服务器必须加上另一个:
Access-Control-Allow-Headers: Authorization, User...
3、Cookie控制(可选)
CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定
Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开`withCredentials`属性。

浏览器将CORS请求分成两类:简单请求和非简单请求,两种都会在头信息之中,增加一个Origin字段。对于简单请求,浏览器直接发出CORS请求。非简单请求的CORS请求,会在正式通信之前,增加一次Options方法HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

与JSONP比较:
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

代理:

解决跨域除了CORS标准方法外,还可以通过代理解决。nodejs和nginx都可以反向代理,解决跨域问题。
原理是,把页面资源放到HTTP服务器,页面的接口请求都使用相对地址。这样网站所有请求都会走到HTTP服务器,HTTP服务器根据请求路径(如路由模块)来区别处理,若请求静态资源就直接返回,如果是接口请求则由HTTP服务器代理发起请求,拿到结果后再返回给页面接口,实现跨域。


JohnsonGH
32 声望1 粉丝