Jsonp原理及实现

        最近做项目,由于前台系统和后台信息发布系统需要部署到不同的服务器上,并且二级域名也不相同,所以经常会遇到一些跨域访问的问题,这些问题基本上可以通过JSONP的方式实现。自己上网找了些JSONP相关的文章来看,做了如下的总结。


1. JSON(JavaScript Object Notation )和JSONP(JSON with Padding)的区别
         JSON和JSONP虽然只有一个字母的差别,但其实他们根本不是一回事儿:JSON是一种数据交换格式,JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问。JSON对于JavaScript开发人员充满魅力的原因在于JSON本身就是Javascript中的对象。
之所以会有跨域这个问题的产生根本原因是浏览器的同源策略限制。

2. 同源策略限制
         同源策略是指阻止代码获得或者更改从另一个域名下获得的文件或者信息。也就是说我们的请求地址必须和当前网站的地址相同。同源策略通过隔离来自不同源的文件或信息来实现对资源的保护。

3. JSONP的作用
         由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。

4.JSONP的产生
         解决同源策略限制的一个相对简单的办法就是在服务器端发送请求,服务器充当一个到达第三方资源的代理中继。虽然是用广泛但是这个方法却不够灵活。另一种方式是使用框架要素( iframe)在当前 Web 页面中创建新区域,并且使用 GET 请求获取任何第三方资源。不过,获取资源后,框架中的内容会受到同源策略的限制。
有一个很巧妙的办法就是在页面中使用动态代码元素(script),代码的源指向服务地址并在自己的代码中加载数据。当这些代码加载执行的时候,同源策略就不会起到限制,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

5.JSONP原理: 
1)首先在客户端注册一个callback, 然后把callback的名字传给服务器。
2)服务器先生成 json 数据。
3)然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp.
4)最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
5)客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)

6.JSONP的具体实现
下面通过一些具体的例子来说明。
1)在本地的JS文件中声明方法,在远程JS中调用,远程JS已经存在。
现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。

        jsonp.html内容如下:




    Jsonp Demo
    
    
    
    


        remote.js的内容如下:

localHandler({"result":"我是远程js带来的数据"});

        但是,细心观察,就会产生这样的疑问:怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?这个问题我们留在下一个例子中解决。


2)在本地的JS文件中声明方法,在远程JS中调用,远程JS通过服务端程序动态生成。
聪明的开发者很容易想到,只要服务端提供的js脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端“我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。
        该实例jsonp.html代码如下:




    Jsonp Demo
    
    


        远程调用端通过Servlet向本地写回js方法的调用:

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

public class JsonpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        //获取回调方法名
        String callback = request.getParameter("callback");
        //获取参数信息
        String url = request.getParameter("param");
        PrintWriter out = response.getWriter();
        if("baidu".equals(url)){
            out.write(callback + "({success:true, url:'http://www.baidu.com'})");
        } else {
            out.write(callback + "({success:false, url:'http://www.google.com'})");
        }
    }
}

        web.xml对该Servlet做配置:




    
        JsonpServlet
        JsonpServlet
    
    
        JsonpServlet
        /JsonpServlet
    


        这次的代码变化较大,不再直接将远程js文件写死,其访问的是远程的服务器端程序,并且JS内容通过远程服务器程序动态生成。以上程序生成的动态的JS文件的内容如下:
localHandler({success:true, url:'http://www.baidu.com'})

        到现在为止,相信你已经能完全理解JSONP的实现原理了!
        使用JS框架实现JSONP的原理是相同的。jquery框架的实现方式如下:




    Jsonp Demo
    
    
    


        是不是有点奇怪?为什么有写flightHandler这个函数呢?而且竟然也运行成功了!原因是jquery在处理jsonp类型的ajax时自动帮你生成回调函数并把数据取出来供success属性方法来调。

        参考文章:1)http://justcoding.iteye.com/blog/1366102

2)http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html

你可能感兴趣的:(JSONP,JSONP,javascript)