×

JSONP实现原理

96
focusOn
2016.12.18 00:29* 字数 665

JSONP:JSON With Padding

含义:可以理解为请求后端API,服务器会在传给浏览器前将JSON数据填充到回调函数(parseResponse)中

主要原理:

1.Script标签,通过src的方式去加载某一个服务器下的资源
2.用Script标签加载资源是没有跨域问题的,可以加载任何类型的文件

以上方式存在一个缺点:

  • 当页面一加载就开始执行,不能异步请求,做到按需加载
  • 需求:从某个服务器获取一段文本内容,获取之后在控制台打印,示意前端代码:
<!DOCTYPE html>
<html>
<head>
 <title>js跨域问题-jsonp</title>
 <!--JSONP方式 JSON with Padding:可以理解为内填充-->
 <!--1.首先定义一个函数用来处理返回的函数-->
 <script type="text/javascript">
 function fn(data){
 console.log(data);
 }
 </script>
 <!--2.从服务端加载需要请求的数据,举例请求地址为:http://api.douban.com/book/subjects?q=javascript&alt=xd&callback=fn1  此地址可以修改q进行搜索豆瓣服务器端的图书资源-->
 <script type="text/javascript" src="http://www.example.com/todo/api/v1.0/tasks?callback=fn"></script>

 

</head>
<body>

</body>
</html>

后端示意代码,以python的flask为例:

# coding=UTF-8
import json
from os import abort
 
from flask import request, Flask, jsonify
 
app = Flask(__name__)
 
tasks = [
    {
        'id': 1,
        'title': u'Buy groceries',
        'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
        'done': False
    },
    {
        'id': 2,
        'title': u'Learn Python',
        'description': u'Need to find a good Python tutorial on the web',
        'done': False
    }
]
 
@app.route('/todo/api/v1.0/tasks', methods=['POST',"GET"])
def create_task():
    print request.args
    # if not request.json or not 'title' in request.json:
    #     abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': "test",
        'description': "hah",
        'done': False
    }
    tasks.append(task)
    # 这里定义callback主要是为了动态返回客户端需要执行的全局函数名称
    callback = request.args.get('callback')
    jsonData = "{\"id\":\"3\", \"name\":\"zhangsan\", \"telephone\":\"13612345678\"}"
    retStr = callback + "(" + json.dumps(task) + ")"
    return retStr
 
if __name__ == '__main__':
    app.debug = True
    app.run()

通过以上方式,我们便通过JSONP的方式成功访问到了服务器跨域的资源。

JSONP优点

它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都 可以运行,
不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

JSONP缺点

它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

Jsonp的执行过程如下:

首先在客户端注册一个callback (如:'jsoncallback'), 然后把callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端得到callback的数值后,要用jsonp1236827957501(......)
把将要输出的json内容包括起来,
此时,服务器生成 json 数据才能被客户端正确接收。
然后以 javascript 语法的方式,生成一个function, function 名字就是传递上来的参数 'jsoncallback'的值 jsonp1236827957501 .
最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,作为参数, 传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法
封装的的success: function (json))里。
可以说jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的)。
JSONP是一种脚本注入(Script Injection)行为,所以有一定的安全隐患。

JavaScript
Web note ad 1