版权声明:本文为博主原创文章,未经博主允许不得转载。
问题描述:
在平时我们写的前端是通过控制层跳转到前端展示页面,而前端再发送请求也是直接到了和在即后台对应的域名和端口,能成功发送请求,也能成功获取数据。但问题是,如果你的首页访问了和你的后台不是同一个域名和端口号的地址,则能成功发送请求,但是返回的数据会被浏览器过滤。
到这里我们知道如果按照平时的方式来访问其他域名和端口是不行的,首先我们来了解一下什么叫跨域请求,什么叫同源策略,怎么实现跨域请求,以及有哪些方法可以来实现。
一、跨域请求:
1、什么是跨域:
简单地理解就是因为JavaScript同源策略的限制,test1.com 域名下的js无法操作test2.com或是test3.com域名下的对象。更详细的说明可以看下表:
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一域名下 | 允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/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://70.32.92.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.js http://script.a.com/b.js | 主域相同,子域不同 | 不允许 |
http://www.a.com/a.js http://a.com/b.js | 同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允许 |
2、什么是同源策略限制:
同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。
3、跨域请求的解决方式:jsonp
(1)、什么是jsonp:
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
(2)、jsonp是怎么解决跨区问题的:
由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。
(3)、实现原理:
在HTML DOM中,Script标签是可以跨域访问服务器上的数据的.因此,可以指定script的src属性为跨域的url,从而实现跨域访问.
这种访问方式是不行的.但是如下方式,却是可以的.
<script src=”http://localhost:18080/test/Test1” type="text/javascript"></script>
这里对返回的数据有个要求,即:服务器返回的数据不能是单纯的如{"Name":"zhangsan"}
(4)、jsonp的原理:如果返回的是这个json字符串,我们是没有办法引用这个字符串的.所以,要求返回的值,务必是var json={"Name":"zhangsan"},或json({"Name":"zhangsan"}) ,或json([{"id":35977,"voteNum":78},{"id":35978,"voteNum":26}])
为了使程序不报错,我们务必还要建立个json函数,函数的名称在发送的时候可以指定。
首先在客户端注册一个callback (如:'jsoncallback'), 然后把callback的名字(如:success_jsonpCallback)传给服务器端对应的处理函数。
服务器先生成需要返回给客户端的 json 数据。然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数(jsoncallback)的值(success_jsonpCallback) 。
最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
客户端浏览器,解析script标签,并将服务器端返回的数据,作为参数,
传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里。
实际上跨域是通过动态增加script来加载数据,无法直接获得数据,所以需要使用回调函数。
4、json 实现跨域请求的方式:
(1)、使用JavaScript 来实现:
前台实现:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <table>
- <tr>
- <td ><span> age: </span><span id="age1" name="age1">0</span></td>
- </tr>
- </table>
- </body>
- <script language="JavaScript" src="js/jquery.js"> </script>
- <script type="text/javascript">
- function jsoncallback(data) {
- var age=data.age;
- alert(age);
- document.getElementById("age1").innerHTML =age;
- }
- </script>
- <script type="text/javascript" src="http://localhost:18080/test/Test1?callback=jsoncallback"></script>
- </html>
其中请求地址中的那个callback变量就是传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback),而后台传递过的参数名称要和定义的回调函数的名称一致。
注意JavaScript的链接,必须在function的下面。
后台实现:
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- //从请求路径中获取回调函数名
- String functionName= request.getParameter("callback");
- System.out.println(functionName);
- response.setCharacterEncoding("GBK");
- response.setContentType("text/json");
- PrintWriter out = response.getWriter();
- //返回的名称和前台定义的回调名称一致
- String stu = functionName+"({\"age\":\"12\",\"name\":\"whd1\"})";
- out.print(stu);
- out.flush();
- out.close();
- }
注意其中要返回的stu,我们发现和之前返回json格式的字符串不同,这里还多了一个functionName 这个就是从前台获取的回调函数的名称,使用jsonp 这个是必须的
如果后台返回的是json数组格式则循环获取每一个json对象在获取其对象属性。
(2)、使用jquery 来实现:( $.getJSON()、$.ajax())
$.getJSON()来实现:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <table>
- <tr>
- <td ><span> name: </span><span id="name1" name="name1">www</span></td>
- <td ><span> age: </span><span id="age1" name="age1">0</span></td>
- </tr>
- </table>
- </body>
- <script language="JavaScript" src="js/jquery.js"> </script>
- <script type="text/javascript">
- $.getJSON("http://localhost:18080/test/Test1?callback=?",function(result) {
- for(var i in result) {
- alert(i+":"+result[i]);
- }
- });
- </script>
- </html>
后台处理代码:
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- //从请求路径中获取回调函数名,这个是jquery 自动生成的
- String functionName= request.getParameter("callback");</span>
- System.out.println(functionName);
- response.setCharacterEncoding("GBK");
- response.setContentType("text/json");
- PrintWriter out = response.getWriter();
- String stu = functionName+"({\"age\":\"12\",\"name\":\"whd1\"})";
- out.print(stu);
- out.flush();
注意:使用 $getJson() 方法来实现的时候callback 参数不能指定具体的值,只能用“?”,jquery会将?号自动替换成自动生成的回调函数的名称。如果直接指定了则不会执行前台的function 这个默认函数而要用户自己定义一个和回调函数名一样的函数。
如果后台返回的是json数组格式则循环获取每一个json对象在获取其对象属性。
$.ajax()来实现:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <table>
- <tr>
- <td ><span> name: </span><span id="name1" name="name1">www</span></td>
- <td ><span> age: </span><span id="age1" name="age1">0</span></td>
- </tr>
- </table>
- </body>
- <script language="JavaScript" src="js/jquery.js"> </script>
- <script type="text/javascript">
- $.ajax({
- url:"http://localhost:18080/test/Test1",
- dataType:'jsonp',
- data:'',
- jsonp:'callbackparam', //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
- //jsonpCallback:'success_jsonpCallback', // 自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
- success:function(data){
- for(var i in data){
- alert(i+ " " +data[i]);
- }
- },
- timeout:3000
- });
- </script>
- </html>
这里注意: 如果定义了jsonpCallback 则回调函数名称使用的是定义的值,如果不定义jsonpCallback 则使用jquery自动生成的回调函数名。
后台实现代码:
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- //从请求路径中获取回调函数名,如果定义了获取定义的,如果没有定义则获取jquery自动生成的
- String functionName= request.getParameter("callbackparam");
- System.out.println(functionName);
- response.setCharacterEncoding("GBK");
- response.setContentType("text/json");
- PrintWriter out = response.getWriter();
- //返回的名称和前台定义的回调名称一致
- String stu = functionName+"({\"age\":\"12\",\"name\":\"whd1\"})";
- out.print(stu);
- out.flush();
- out.close();
- }
如果后台返回的是json数组格式则循环获取每一个json对象在获取其对象属性。
从中我们能看到jsonp 和jsonpCallback两个参数的作用了。
定义jsonpCallback 和不定义两种请求中获取的回调函数的名称:
从获取的数据我们看到了 定义和不定义的两种方式请求获取的回调函数名称,即自定义和jquery 自动生成。
发送请求时需要传一个callback的回调函数名到服务器端,服务器端拿到这个回调函数名,再将返回数据用参数的形式反回到客户端,这样客户端就能够调到。
所以发送请求URL的地址后面一定要上jsoncallback=?这样的参数,jquery会将?号自动替换成自动生成的回调函数的名称。
所以最终的实际请求为:http://api.taobao.com/apitools/ajax_props.do&jsoncallback=jsonp1322444422697
所以和ajax的方式想比较,也就是callback函数一个是自动生成的函数名,一个是手工指定的函数名。