跨域请求
跨域的相关概念
当请求访问其他服务器的数据时,客户端会出现跨域问题
跨域问题是由于javascript语言安全限制中的同源策略造成的
简单来说,同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合
URL | 说明 | 通信 |
http://www.a.com/a.js http://www.a.com/b.js |
同一域名 | 允许 |
http://www.a.com/file/a.js http://www.a.com/lib/b.js |
同一域名 不同文件夹 |
允许 |
http://www.a.com:8080/a.js http://www.a.com/b.js |
同一域名 不同端口 |
不允许 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名 不同协议 |
不允许 |
http://www.a.com/a.js http://59.65.233.233/b.js |
域名IP |
不允许 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同 子域不同 |
不允许 |
http://www.a.com/a.js http://www.different.com/b.js |
不同域名 | 不允许 |
跨域的例子:
在tomcat6中部署了项目TestA,在tomcat7中部署了项目TestB(tomcat6的端口改为8081)
TestA中的index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html> <head> <title>A</title> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script> </head> <body> This is my A page. <br> </script> <script type="text/javascript"> function sayHello(a){ alert('B.word is ' + a); } $.getJSON('http://localhost:8080/TestB/index.jsp', function(data){ sayHello(data); }); </script> </body> </html>
于是出现如下错误:
解决方法
1.<script>标签及jsonp
浏览器会阻止ajax请求非同源的内容,但没有限制<script>标签来访问非同源的内容,也没有限制使用动态添加<script>标签,所以可以采用这种方式打破这种限制。
TestA中index.jsp:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <!DOCTYPE HTML> 3 <html> 4 <head> 5 <title>A</title> 6 <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script> 7 </head> 8 <body> 9 This is my A page. <br> 10 <script type="text/javascript" src="http://localhost:8080/TestB/index.jsp"></script> 11 <script type="text/javascript"> 12 function sayHello(){ 13 alert('B.word is ' + a); 14 } 15 sayHello(); 16 </script> 17 </body> 18 </html>
TestB中index.jsp:
<% String str="test1"; out.println("var a = '"+str+"';"); //返回值 %>
解释:
第10行,利用<script>标签请求到了TestB中的资源,请求返回是一个js文件,这个js的内容就是“var a='test1'”,因此在第15行调用sayHello()时能够获取到a的值
改进:
尤其,我们利用动态生成<script>标签的方法来实现动态跨域请求
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html> <head> <title>A</title> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script> <script type="text/javascript"> window.onload = function (){ var scriptBlock = document.createElement("script"); scriptBlock.src = "http://localhost:8080/TestB/index.jsp"; scriptBlock.type = "text/javascript"; scriptBlock.language = "javascript"; document.getElementsByTagName("head")[0].appendChild(scriptBlock); //setTimeout(sayHello,1000);//延时执行 scriptBlock.onload=sayHello; } function sayHello(){ if(document.readyState=="complete") alert('B.word is ' + a); } </script> </head> <body> This is my A page. <br> </body> </html>
注:因为chrome不支持onreadystatechange,所以改用onload在IE和Chrome下都能运行
同样通过延时执行也能弹出结果,但是并不妥当。
利用jquery获取JSONP:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html> <head> <title>A</title> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script> <script type="text/javascript"> function sayHello(data){ alert(data.Email) } $.ajax({ url: 'http://localhost:8080/TestB/somejson.json', dataType: "jsonp", jsonp: "callback" }) </script> </head> <body> This is my A page. <br> </body> </html>
其中somejson.json文件:
sayHello({"Email":"jellybaobao@139.com"})