`

jsonp详解

    博客分类:
  • js
阅读更多

1. 什么是jsonp?

       JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。

 

2.JSONP有什么用?

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

 

3. jsonp是怎么产生的?

       一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

       不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>);

       于是,我们可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;

      恰巧,我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

      这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

      客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

      为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

 

4. Jsonp原理: 

    1)首先在客户端注册一个callback, 然后把callback的名字传给服务器;

    2)服务器先生成 json 数据;

    3)服务端以 javascript 语法的方式,生成一个function , function 名字就是参数 jsonp中定义的名字;

    4)服务端最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端;

    5)客户端浏览器解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里(动态执行回调函数)。

 

5. jsonp用法:

 先来看几个示例:

示例1:

客户端jsonp1.html(所有测试文件都放在根目录WEB-INF下): 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript" src="http://172.19.137.52:8080/rm-admin/remote1.js"></script>
</head>
<body>
</body>
</html>
 服务端remote1.js(远程服务端的url:http://172.19.137.52:8080/rm-admin) 
alert("我是远程服务器");
 运行结果: 

     在客户端浏览器中弹出提示框:我是远程服务器。

 

示例2:

客户端jsonp2.html: 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<head>
    <title></title>
    <script type="text/javascript">
    	var localHandler = function(data){
    		alert("本地函数远程调用remote2.js,获取到的数据是:"+data.result);
    	}
    </script>
    
    <!-- 注意:JavaScript的链接,必须在function的下面。 -->
    <script type="text/javascript" src="http://172.19.137.52:8080/rm-admin/remote2.js"></script>
</head>
<body>
</body>
</html>

 服务端remote2.js 

localHandler({"result" : "我是远程服务器的数据"});

  运行结果: 

      在客户端浏览器中弹出提示框:我是远程服务器的数据。

 

示例3(jsonp的原生写法):

客户端jsonp3.html: 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<head>
    <title></title>
    <script type="text/javascript">
    	var flightHandler = function(data){
    	   alert("查询到的航班结果是:票价为"+data.price+"元,余票为"+data.tickets+"张。");
    	}

    	// 动态生成调用服务端的js脚本
    	// 远程服务端url
    	var url = "http://172.19.137.52:8080/rm-admin/flight/result.htm?code=CA1401&callback=flightHandler";
    	
	// 创建scrip标签,并设置src属性
    	var script = document.createElement("script");
    	//script.type = "text/javascript";  
    	//script.src = url;
    	// 也可以这么写:
    	script.setAttribute('type', "text/javascript"); 
    	script.setAttribute('src', url); 
    	
    	// 将script标签加入到header
    	document.getElementsByTagName('head')[0].appendChild(script);
    </script>
</head>
<body>
</body>
</html>

 服务端FlightController.java: 

package com.cnsuning.rm.admin.web.controller;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 航班管理 Controller
 * 
 * @author guwq
 */
@Controller
@RequestMapping("/flight")
public class FlightController extends BaseController {

	@RequestMapping(value = "/result", method = RequestMethod.GET)
	@ResponseBody
	public void result(HttpServletRequest request, HttpServletResponse response) {
	    StringBuffer result = new StringBuffer();
	    
	    // 打印获取到的参数
	    String code = request.getParameter("code");
	    String callback = request.getParameter("callback");
	    System.out.println("code==="+code);
	    System.out.println("callback==="+callback);
	    
	    // 拼接jsonp返回结果,在实际情况中,返回结果由后台获取
	    //result = "flightHandler({'price' : '1000', 'tickets' : '50'});";
	    result.append("flightHandler");
	    result.append("({");
	    result.append("\"price\":").append("1000").append(",");
	    result.append("\"tickets\":").append("50");
	    result.append("})");
	    
            // 注意ContentType类型一定要是application/x-javascript
	    response.setContentType("application/x-javascript;charset=UTF-8");
	    PrintWriter out = null;
	    try {
		out = response.getWriter();
		out.println(result);
		out.flush();
		out.close();		
	    } catch (IOException e) {
		logger.error("setResponse IOException" + e.getMessage(), e);
	    } finally {
		if(out != null){
			out.close();
		}
	    }
	}
}
  运行结果: 

       在客户端浏览器中弹出提示框:查询到的航班结果是:票价为1000元,余票为50张。

 

示例4(jsonp的ajax写法):

客户端jsonp4.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<head>
    <title></title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.js"></script>
    <script type="text/javascript">
    	$(function(){
            // 使用ajax来调用jsonp
    	    $.ajax({
                type: "get", //jsonp默认为get请求,即使写post也会转换成get方式
                async: false, // jsonp默认为false,即使写true也会转换成false
                url: "http://172.19.137.52:8080/rm-admin/flight/result.htm", // 服务端地址
                data: {"code" : "CA1405"}, // 入参
                dataType: "jsonp", // jsonp调用固定写法
                jsonp: "callback", // 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)。即:?callback=xxx中的callback部分
                jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据。即:?callback=xxx中的xxx部分
                success: function(data){ // 调用成功之后的方法
                    alert("查询到的航班结果是:票价为"+data.price+"元,余票为"+data.tickets+"张。");
                },
                error: function(){ // 调用失败之后的方法
                    alert('error');
                }
            });
        });
    </script>
</head>
<body>
</body>
</html>

注解:

注解1:参数jsonp: "callback" 不是必须的,如果该参数为空,则 默认为:jQuery+一个随机字符串,例如:jQuery182025588105828501284_1453863135570,并且执行结果和加上该参数一样。

注解2:参数jsonpCallback:"flightHandler"是必须的,如果该参数为空,则调用失败。

注解3:如果自定义回调函数(即jsonpCallback参数)的函数体不为空,则优先执行该自定义函数,然后执行success中的代码:

 客户端jsonp5.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<head>
    <title></title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.js"></script>
    <script type="text/javascript">
    	$(function(){
            // 使用ajax来调用jsonp
    	    $.ajax({
                type: "get", //jsonp默认为get请求,即使写post也会转换成get方式
                async: false, // jsonp默认为false,即使写true也会转换成false
                url: "http://172.19.137.52:8080/rm-admin/flight/result.htm", // 服务端地址
                data: {"code" : "CA1405"}, // 入参
                dataType: "jsonp", // jsonp调用固定写法
                jsonp: "callback", // 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)。即:?callback=xxx中的callback部分
                jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据。即:?callback=xxx中的xxx部分
                success: function(data){ // 调用成功之后的方法
                    alert("success");
                },
                error: function(){ // 调用失败之后的方法
                    alert('error');
                }
            });
        });

        // 自定义回调函数
        function flightHandler(data){
	   		alert("(普通写法)查询到的航班结果是:票价为"+data.price+"元,余票为"+data.tickets+"张。");
		}
		// 或用原生写法
		var flightHandler = function(data){
			alert("(原生写法)查询到的航班结果是:票价为"+data.price+"元,余票为"+data.tickets+"张。");		
		}
        
    </script>
</head>
<body>
</body>
</html>

 

 服务端同示例3中的服务端,运行结果也同示例3的运行结果。

 

 

 

 

分享到:
评论

相关推荐

    Node.js返回JSONP详解

    Node.js中实现JSONP详解 Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它使用事件驱动、非阻塞I/O模型,使得它非常适合于网络应用,尤其是Web服务器端开发。JSONP(JSON with Padding)是一种用于从不同域...

    jsonp.pdf文件

    JSONP详解** **基本原理**:JSONP利用了`&lt;script&gt;`标签不受同源策略限制的特点。当需要从不同域获取数据时,可以通过在客户端动态创建一个`&lt;script&gt;`标签,并将请求URL设置为其`src`属性值的方式,实现跨域请求。...

    jsonp json ajax跨域调用

    ### JSON与JSONP详解 #### 一、JSON概述 **JSON**(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON的流行主要得益于以下几点优势: 1. **跨平台性...

    跨域恳求的完善解决方法(JSONP, CORS)_.docx

    #### 二、JSONP详解 ##### 2.1 JSONP原理 JSONP(JSON with Padding)是一种利用JavaScript的`&lt;script&gt;`标签不受同源策略限制的特点,实现跨域数据传输的方法。其基本思想是,客户端通过创建一个`&lt;script&gt;`标签,...

    Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别.docx

    ### Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别 #### 一、Jsonp 关键字详解 Jsonp(JSON with Padding)是一种跨域数据交互协议,它允许在一个网页中请求并获取另一个域的服务端数据。Jsonp 的工作...

    json与jsonp知识小结(推荐).docx

    #### 四、JSONP详解 **JSONP**(JSON with Padding)是一种解决跨域问题的技术方案。由于JavaScript的安全限制,默认情况下不允许不同源之间的脚本互相调用,而JSONP通过动态插入`&lt;script&gt;`标签并利用`src`属性可以绕...

    详解如何在Vue项目中发送jsonp请求

    在页面a中由前端发送一个jsonp请求到客户方,得到一个token值 前端得到token值后向自己后端发送一个请求,后端根据token去redis(token的值就是redis里的key)里取值(key=token的值,value=用户信息等)判断用户是否已...

    详解JSON和JSONP劫持以及解决方法.docx

    "详解JSON和JSONP劫持以及解决方法" 本文主要介绍了JSON和JSONP劫持的概念、攻击过程、解决方法以及实例代码,旨在帮助读者深入理解这两种攻击方式,并提供实际有效的解决方法。 JSON劫持 JSON劫持,也称为JSON ...

    jsonp原理.txt

    ### JSONP原理详解 #### 一、什么是JSONP? JSONP(JSON with Padding)是一种用于解决浏览器同源策略限制的方法,允许网页从不同域名的服务器上加载数据。它利用了`&lt;script&gt;`标签不受同源策略限制的特点来实现...

    Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

    JSONP和JSON都是数据交换格式,但它们的使用场景和工作方式存在明显差异。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它以易于阅读和编写的形式存储和表示数据,易于人阅读和编写,同时也易于...

    全面解析Ajax和jsonp使用总结

    【Ajax和Jsonp详解】 Ajax(Asynchronous JavaScript and XML)是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。它的核心是通过JavaScript创建XMLHttpRequest对象(现在大多数浏览器支持的API是...

    JSONP跨域请求实例详解

    JSONP(JSON with Padding)是一种跨域数据交互协议,它利用了浏览器的同源策略的例外,即允许页面加载来自不同源的`&lt;script&gt;`标签。这种方法主要用于解决现代浏览器中的跨域数据访问问题,因为JSONP不受同源策略的...

    java中的JSONP使用实例详解

    JSONP(JSON with Padding)是一种跨域数据交互协议,它利用了`&lt;script&gt;`标签可以跨域加载资源的特性来实现浏览器与服务器之间的数据通信。在JavaScript中,由于同源策略的限制,Ajax通常无法进行跨域请求,而JSONP...

    jsonp格式前端发送和后台接受写法的代码详解.docx

    ### JSONP格式前后端交互详解 #### 一、JSONP简介 JSONP(JSON with Padding)是一种跨域数据请求的方法,通常用于解决浏览器同源策略限制下的数据获取问题。同源策略是浏览器的一种安全措施,它限制了一个网页脚本...

    Angular2 http jsonp的实例详解

    这篇实例详解主要关注的是使用HTTP和JSONP模块来发送GET和POST请求。Angular的HTTP服务是基于浏览器的XMLHttpRequest (XHR) 和 JSONP API实现的,这两种API允许前端与后端进行异步数据交互。 1. **HttpModule和...

Global site tag (gtag.js) - Google Analytics