关于跨域的ajax——Cross-Origin Resource Sharing (CORS)
CORS浏览器支持:Firefox3.5+,Safari4+,Chrome,SafariforiOS,andWebKitforAndroid
//页面A: http://shawn.test2.com/crossAjax.html function create(){ var objXMLHTTP = new XMLHttpRequest(); objXMLHTTP.open('GET', 'http://www.test.com:8080/jsp/json.jsp', true); //objXMLHTTP.setRequestHeader("hello","world"); objXMLHTTP.onreadystatechange = function(){ if(objXMLHTTP.readyState == 4){ alert(objXMLHTTP.responseText); } }; objXMLHTTP.send(null); } //后端页面B: http://www.test.com:8080/jsp/json.jsp <% // 允许来自 http://shawn.test2.com(默认端口80)的请求。 response.setHeader("Access-Control-Allow-Origin","http://shawn.test2.com"); // 允许所有 //response.setHeader("Access-Control-Allow-Origin","*"); /* cookie 设置发送到浏览器端,不会生效。 String cookieName="Sender"; Cookie cookie=new Cookie(cookieName, "Test_Content"); cookie.setMaxAge(10); //存活期为10秒 response.addCookie(cookie); */ String str = ""; str += "{"; str += "\"result\":1"; str += ",\"data\":[5,7]"; str += "}"; out.print(str); %>
允许多个域名?可以考虑把域名做一个白名单,读取到服务器,然后再进行匹配。
上述的这种跨域请求有几个限制:
1.不会携带cookie信息到服务器端;服务器端也不能写cookie到客户端;
2.不能通过setRequestHeader()自定义头部信息;
3.getAllResponseHeaders()返回值为空字符串。
关于预检请求(PreflightedRequest):
事实上,如果用户通过setRequestHeader自定义了头部信息,浏览器会默认先发送一个请求,用了判断请求是否合法,如果不通过,
ajax请求就失败了,如果通过了,浏览器会再发一次请求,读取服务器的返回数据。
例如,上述例子中,如果调用:
objXMLHTTP.setRequestHeader("hello","world");
则浏览器会发出请求,内容为空,请求头部为:
OPTIONS/jsp/json.jspHTTP/1.1
Host:www.test.com:8080
User-Agent:Mozilla/5.0(WindowsNT6.1;WOW64;rv:8.0.1)Gecko/20100101Firefox/8.0.1
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language:zh-cn,zh;q=0.5
Accept-Encoding:gzip,deflate
Accept-Charset:GB2312,utf-8;q=0.7,*;q=0.7
Connection:keep-alive
Origin:http://shawn.test2.com
Access-Control-Request-Method:GET
Access-Control-Request-Headers:hello
注意,头部请求中,多出几个选项:
Origin:http://shawn.test2.com
Access-Control-Request-Method:GET
Access-Control-Request-Headers:hello
如果想采用POST方式提交ajax数据,需要手动设置
function create(){ var objXMLHTTP = new XMLHttpRequest(); objXMLHTTP.open('POST', 'http://www.test.com:8080/jsp/json.jsp', true); objXMLHTTP.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); objXMLHTTP.setRequestHeader("hello", "world"); objXMLHTTP.onreadystatechange = function(){ if(objXMLHTTP.readyState == 4){ alert(objXMLHTTP.responseText); } }; objXMLHTTP.send("userName=shawn"); }
因为这里定义请求头,所以后端也需要做设置支持:
<% response.setHeader("Access-Control-Allow-Origin","http://shawn.test2.com"); //response.setHeader("Access-Control-Allow-Methods","GET,POST"); //逗号分隔;默认可以不设置。 response.setHeader("Access-Control-Allow-Headers","Content-Type,hello"); //逗号分隔 //预检测被缓存时间:30秒;默认可以不设置。在这个时间内,用户再次请求改数据,可以跳过预检测阶段。 // 在firefoxV8里面,发现这个设置并没有生效。chromeV14、Safari5是生效的。 //response.setHeader("Access-Control-Max-Age","30"); String str = ""; str += "{"; str += "\"result\":1"; str += ",\"data\":[5,7]"; str += ",\"userName\":" + request.getParameter("userName"); str += "}"; out.print(str); %>
浏览器支持预检请求:Firefox3.5+,Safari4+,andChrome
关于携带验证信息的请求(CredentialedRequests)
如果希望把cookie信息、HTTP授权信息、客户端的SSL证书等发送到服务器端。可以如下设置:
objXMLHTTP.withCredentials = true; //允许ajax请求携带cookie信息 // 服务器端,同样要做调整: response.setHeader("Access-Control-Allow-Credentials", "true");
注意:
1.这里面,请求携带的是服务器所在域名的cookie。例子中,就是www.test.com(包括test.com)的cookie信息。
2.如果服务端这时候设置了cookie,那么它是起作用的,默认挂在www.test.com域名下。
IE8+下的跨域对象:
IE8+支持一个XDomainRequest(XDR)对象,用来进行跨域的ajax通信。
XDomainRequest相比较普通的Ajax对象,有以下限制:
1.不支持Cookie的发送和接收;
2.除了Content-type,不能设置其他请求头部;
3.无法读写返回头部;
4.仅支持GET/POST方法。(其它的方法的是?)
//http://shawn.test2.com/crossAjax.html function createXDR(){ var xdr = new XDomainRequest(); xdr.onload = function(){ alert(xdr.responseText); }; xdr.onerror = function(){ alert("An error occurred."); }; //测试中,发现仅仅只能通过GET方式传值。 xdr.open("GET", "http://www.test.com:8080/jsp/jsonie.jsp"); // IE8 下报错 // xdr.contentType = "application/x-www-form-urlencoded"; // xdr.send(); // 后端无法读取到POST的内容。不知道为何? // xdr.send("userName=shawn"); } // http://www.test.com:8080/jsp/jsonie.jsp <% response.setHeader("Access-Control-Allow-Origin","*"); // allow all String str = ""; str += "{"; str += "\"result\":1"; str += ",\"data\":[5,7]"; str += ",\"userName\":" + request.getParameter("userName"); str += "}"; out.print(str); %>
总的来说,IE下出于安全的考虑,对于跨域的ajax限制很大,功能也弱。XDomainRequest也支持progres、timeout等事件,更多内容可以参考MSDN.
参考资料:
https://developer.mozilla.org/en-US/docs/HTTP_access_control
http://msdn.microsoft.com/ZH-CN/library/cc288060
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control
《javascript高级程序设计3》
相关推荐
结束数据方法的参数,该如何定义?-- 集合为自定义实体类中的结合属性,有几个实体类,改变下标就行了。<input id="add" type="button" value="新增visitor&quo