你的位置:首页 > Java教程

[Java教程]jQuery的jsonp跨域是这么回事.


实现跨域请求的有iframe,img,script中的src属性.
那么jquery是如何解决跨域请求的呢?

一:
项目jsonp2中有个app.js文件,代码如下:

function app(json){  alert(json['name']);}

项目jsonp1中的index.html

<script type="text/javascript" src="http://127.0.0.1:8020/jsonp2/js/app.js"></script><script type="text/javascript">  app({'name':"guoyansi",'age':25});</script>

执行结果:
这里的app方法并没有申明,怎么就能调用了呢?
这里的第一个script出现了跨域请求,src指向的是jsonp2中的app.js
而在app.js中申明了app方法.
我们现在在火狐中查看index.html的源码,点开app.js的script

结论:从外部引入的app.js最终会被加载到浏览器中,渲染成这样:

<script type="text/javascript">  function app(json){  alert(json['name']);}</script>

根据上面的结论
我们如果利用script跨域向后台发送一个请求,
我们在后端返回一段js代码,前端不就可以调用了吗?
现在我们来验证假设.
我们用java为例子:
新建javaweb项目并且新建一个servlet,
这个servlet返回一个js代码;

package servelt;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Jsonp2 extends HttpServlet {  public void doGet(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    response.setContentType("text/javascript;charset=utf-8");//jsonp其实回写的就是一段javascript代码    //或者:response.setContentType("text/plain;charset=utf-8");    PrintWriter out = response.getWriter();    out.print("app({'name':'思思博士','age':'25'})");    out.flush();    out.close();  }  public void doPost(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    doGet(request, response);  }}

新建另外一个项目并且新建一个index.html页面

<!DOCTYPE html><html>  <head>    <meta charset="utf-8" />    <title></title>    <script type="text/javascript">      function app(json){        console.log(json);      }    </script>    <script type="text/javascript" src="http://192.168.6.130:8080/jp/Jsonp2"></script>  </head>  <body>      </body></html>

上面的第二个script直接执行了这个新的项目上的servlet.
并且最终被浏览器解析成如下格式:

<script type="text/javascript">  app({'name':'思思博士','age':'25'})</script>

index.html最终的页面变成这个样子:

<!DOCTYPE html><html>  <head>    <meta charset="utf-8" />    <title></title>    <script type="text/javascript">      function app(json){        console.log(json);      }    </script>    <script type="text/javascript">      app({'name':'思思博士','age':'25'})    </script>  </head>  <body>      </body></html>

上面的代码我想大家都知道是怎么执行的了吧.
上面的代码返回的js代码的方法调用时时在服务器端写死的.我们也可以从客户顿指定要返回的反法调用名.
修改servlet:

package servelt;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Jsonp2 extends HttpServlet {  public void doGet(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    response.setContentType("text/javascript;charset=utf-8");//jsonp其实回写的就是一段javascript代码    String appMethod=request.getParameter("appMethod");    PrintWriter out = response.getWriter();        out.print(appMethod+"({'name':'思思博士','age':'25'})");    out.flush();    out.close();  }  public void doPost(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    doGet(request, response);      }}

在客户端指定要服务器要返回的js方法,添加appMethod参数,修改index.html.

<!DOCTYPE html><html>  <head>    <meta charset="utf-8" />    <title></title>    <script type="text/javascript">      function app(json){        console.log(json);      }    </script>    <script type="text/javascript" src="http://192.168.6.130:8080/jp/Jsonp2?appMethod=app"></script>  </head>  <body>      </body></html>

上面的例子都是返回一段可执行的js代码,来调用本地的方法.
我们对上面的例子进行封装.java代码保持不变.

(function($){  $.gys=function(opt){    var scriptCode=(new Date()).getTime();    //拼接script标签    var html="<";    html+="script id='script"+scriptCode+"' type='text/javascript' src='"+opt.src+"?"+opt.callbackName+"="+opt.callback+"'>";    html+="<";    html+"/script>";    //申明一个全局的方法变量供远程返回的js方法的调用,方法名有callback指定    window[opt.callback]=function(json){      opt.success(json);//调用当前参数的方法      $("#script"+scriptCode).remove();//删除script标签    }    $("head").append(html);//插入script标签            }})(jQuery);

调用:

$(function(){  $.gys({    callbackName:"appMethod",    callback:"app",    src:"http://192.168.6.130:8080/jp/Jsonp2",    success:function(data){      console.log(data);    }  });        });

看到这个有没有觉得和jquery的jsonp有点像了啊.
我们现在看看jquery的jsonp.
jsonp其实用的就是上面的原理

我们看看jquery的jsonp用法.

$.ajax({  type:"get",//jsonp只能触发get请求  url:""//跨域url  dataType:"jsonp",  jsonp:"",//对应上面封装的callbackName  jsonpCallback:"",//对应上面封装的callback  data:{},//提交参数  beforeSend:function(){    //jsonp 方式此方法不被触发。原因是这里已经不是ajax事件了.  },  success:funciton(data){    //参数jsonpCallback的方法调用这里的success  },  error:function(){    //这里不是ajax了,所以这个方法也不会触发.  }});

jquery中把jsonp和ajax整合在一起了具有一定的迷惑性,ajax是不具有跨域请求的,
另外jsonp使用的核心也不是ajax的另外这样的jsonp是不具有post请求的.
$.getJSON()和$.getScript()都是jsonp的高级封装.