JS跨域
跨域概念
跨域是浏览器遵循同源策略,对页面脚本的安全限制,不允许Javascript请求不同域的数据。
跨域的本质就是要解决同源策略的限制!假如有地址 http://www.example1.com:8080/a.jsp,如下请求是不符合同源策略限制的:
http://www.example1.com:8081/a.jsp 端口不一致
http://www.example2.com:8080/b.jsp 域名不一致
https://www.example1.com:8080/a.jsp 协议不一致
跨域之JSONP
JSONP跨域是利用<script>标签没有跨域限制的特性,通过其src属性模拟js文件加载,请求不同域的地址,返回符合Javascript语法的数据进行处理,从而间接实现跨域。
我们知道HTML中可以引入其他域的js、css等文件,JSONP正是利用这个特性,把src替换成我们要请求的不同域地址。服务器接收到请求后,把JSON数据包到回调函数中响应,实际上<script>的src属性仍旧加载了一段Javascript代码,但这段代码包含了我们服务器响应的数据。页面收到响应后可以像处理一般Javascript脚本一样,进行调用、处理。
JSONP原理示例
服务端接口:
1 @RequestMapping(value="/getUser", method=RequestMethod.GET) 2 @ResponseBody 3 public String getUser(String callback, Integer id) { 4 String json = "{'id':'123', 'name':'xlog2n'}"; 5 String jsonp = callback + "(" + json + ")"; 6 return jsonp; 7 }
前端请求:
1 <script type="text/javascript"> 2 // 预先定义好回调函数 3 function handleUser(user) { 4 alert(user.id + ":" + user.name); 5 } 6 </script> 7 8 <!-- 实际的JSONP是动态创建script标签 --> 9 <script type="text/javascript" src="http://xlog2n.com/getUser?callback=handleUser&id=123"></script>
实际使用jQuery进行JSONP请求时,<script>标签是动态创建的,<script>标签的src属性指定了不同域的/getUser接口,并且传递了callback指明回调函数的名称,当src加载完成后,实际是一段执行handleUser函数的Javascript代码,参数是从服务端响应回来的JSON数据,其实JSONP就是JSON + P(包装):
handleUser({'id':'123', 'name':'xlog2n'})
JSONP原理简单、兼容性好,jQuery发送JSONP请求也很方便,但是JSONP只支持GET方式的请求,对于POST跨域请求就无能为力了,究其原因<script>标签的src属性发出的请求和<img src=""/>一样都是GET请求,所以JSONP无法支持POST请求!
jQuery JSONP调用示例
jquery把jsonp跨域请求集成到了ajax方法中,jsonp参数指定了回调参数的key,以下示例中我们在后端可以使用 request.getParameter('callback')获取回调函数的名称:
1 $.ajax({ 2 url: 'http://xlog2n.com/getUser', 3 dataType: 'jsonp', 4 jsonp: 'callback', 5 success: function(user) { 6 alert(user.id + ":" + user.name); 7 } 8 });
跨域之CORS
CORS是跨域资源共享标准,提供了一组HTTP头信息,用来描述服务器可以接受哪些来源、哪些方式的请求,从而保证了服务器可以进行跨域请求的控制,只接受符合要求的跨域请求。
服务端响应头设置
使用CORS跨域,只需要在反向代理如nginx中设置以下响应头(也可以程序中设置,如HttpServletResponse.setHeader方法)
1 server { 2 listen 80; 3 server_name xlog2n.com; 4 location / { 5 add_header 'Access-Control-Allow-Origin' '*'; 6 add_header 'Access-Control-Allow-Methods' 'POST,GET,PUT,DELETE'; 7 add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,Cache-Control, ......'; 8 add_header 'Access-Control-Allow-Credentials' 'true'; 9 ...... 10 ...... 11 proxy_pass http://127.0.0.1:8080; 12 } 13 ...... 14 ...... 15 }
第一个头信息Access-Control-Allow-Origin表示服务端接受的跨域请求来源,星号表示接受任何来源,我们也可以指定一个域名,只接受该域名下的跨域请求。
第二个头信息Access-Control-Allow-Methods表示服务端接受的跨域请求方法,示例中只接受POST、GET、PUT、DELETE。
第三个头信息Access-Control-Allow-Headers表示服务端接受的跨域请求头信息,在需要对请求头进行访问控制时,设置该头信息。
第四个头信息Access-Control-Allow-Credentials表示服务端接受附带身份验证信息(Cookie)的跨域请求。要特别注意,如果设置该头信息为true,Access-Control-Allow-Origin不能设置为星号,否则附带身份验证信息的请求会失败。
预测请求
大家可能注意到,有些跨域请求会多发起一个请求OPTIONS请求,其实这个OPTIONS请求就是预测请求。预测请求是浏览器主动发起的,用来测试服务端是否支持这个即将发起的跨域请求。并非所有的跨域请求都会先发送一个预测请求,预测请求是符合条件才触发的。
- 当跨域请求是非GET请求时
- 当跨域请求设置了Accept、Accept-Language(请自行百度会触发的所有头信息)
- 当跨域请求设置了Content-Type头,但Content-Type值不为 application/x-www-form-urlencoded 或者 text/plain 或者 multipart/form-data 之一时
预测请求只有响应头,没有响应体。预测通过后实际的请求才会发起,也会收到相应的响应体。
CORS跨域POST请求示例
上文说到JSONP不支持POST请求,但CORS可以很方便的使用POST发送大量数据到后端:
1 <html> 2 <head> 3 <script src="jquery.min.js" type="text/javascript"></script> 4 <script src="jquery.json.min.js" type="text/javascript"></script> 5 </head> 6 <body> 7 <button>TEST</button> 8 9 <script type="text/javascript"> 10 var orderInfo = { 11 itemId: '1600000000000000301', 12 issueNo: 1, 13 skuNum: 1, 14 payPassword: '011455e004151e30fd1413da54e3d77d', 15 balanceFee: 0, 16 onlineFee: 100, 17 jingBeanFee: 0, 18 couponParams: [], 19 mobile: '158****6060', 20 activityType: 1, 21 screen: '111', 22 uuid: '78043a633e5a440bad90639c67225beb' 23 }; 24 25 $('button').on('click', function() { 26 var body = $.toJSON(orderInfo); 27 28 /* 29 // 方式一:使用原生JS发送Ajax POST跨域请求 30 var xhr = new XMLHttpRequest(); 31 if(xhr) { 32 xhr.open('POST', 'http://xlog2n.com/order', true); 33 xhr.setRequestHeader('Content-Type', 'application/json'); 34 xhr.onreadystatechange = function() { 35 if (xhr.readyState === 4) { 36 if (xhr.status === 200) { 37 alert(xhr.responseText); 38 } else{ 39 alert('错误:' + xhr.status); 40 } 41 } 42 }; 43 xhr.send(body); 44 } 45 */ 46 47 // 方式二:使用jQuery发送Ajax POST跨域请求 48 $.ajax({ 49 url: 'http://xlog2n.com/order', 50 type: 'post', 51 dataType: 'JSON', 52 data: body, 53 headers: {'Content-Type':'application/json'}, 54 success: function(data) { 55 alert(data); 56 } 57 }); 58 }); 59 60 </script> 61 </body> 62 </html>
CORS是比较新的标准,所以各浏览器支持的情况不一样,尤其是那个什么6、7、8,但是CORS跨域支持POST等请求方法,可以很好的支持大数据的提交。和JSONP各有优劣,使用哪种方式还需您自己定夺!!!
IFrame跨域问题
未完待续...

浙公网安备 33010602011771号