JSONP的原理及应用

JSONP 的原理及应用

浏览器的同源策略:ajax跨域发送请求,浏览器不接受数据

但是带有src属性的可以跨域,如script,JSONP就是利用的这种方式

同源策略参考:

https://www.zhihu.com/question/25427931/answer/30848852
https://www.zhihu.com/question/31459669
https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

JSONP 技术

jsonp是一种技术,一种绕过跨域的技巧

禁止ajax跨域

下面是使用ajax进行的向百度发送请求,这种情况就是跨域请求,浏览器会禁止接收数据

    <a onclick="sendMsg();">发送</a>
    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function sendMsg() {
            $.ajax({
            url:'https://www.baidu.com',
            type:'GET',
            success:function (arg) {
                console.log(arg);//使用ajax(本质是使用的XMLHttprequest) 浏览器的同源策略会禁止接收不同域名的内容
                /*
                XMLHttpRequest cannot load https://www.baidu.com/.
                No 'Access-Control-Allow-Origin' header is present on the requested resource.
                Origin 'http://127.0.0.1:8000' is therefore not allowed access.
                */
            }
        })
        }
    </script>

jsonp原理 js代码的执行

jsonp利用scipt标签的src可以跨域

在jsonp的head中创建两个js,第一个是js函数,第二个是执行js函数,关键是函数名一致

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/common.js"></script>
    <script src="/static/common2.js"></script>
</head>

程序从上往下执行,函数f1,后面执行函数f1并传递参数hello,最终的结果就是页面显示hello

common

function f1(arg) {
    alert(arg);
}

common2

f1('hello');  // 传递的参数hello

JSONP实现

通过点击发送标签,js在head创建script标签,script访问http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403,

返回的数据存放在浏览器的内存中

返回数据是list(),就是执行list函数。参数是返回值中的内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/common.js"></script>
	//最终就是在这里创建的script标签	
</head>
<body>
    <a onclick="sendMsg();">发送</a>
    <script>
        function sendMsg() {
            var tag = document.createElement('script');  //创建标签
            tag.src ="http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403";//这里面的返回的数据是list()  里面的数据是字典的形式
            document.head.appendChild(tag); //找到head标签并添加
        }
    </script>
</body>
</html>

common

//list和返回的名称一致
function list(arg) {
    console.log(arg);
}

结果:

传入的参数是字典类型的,返回的是对象

jsonp 应用--API

模拟两个网站,一个是提供数据的网站api,数据是json格式的,设置域名是www.s4.com,端口8001

另一个www.s5.com,要访问s4的数据

存放api的网站

def users(request):
    # v = request.GET.get('callback')
    # print('请求is coming')
    user_list = [
        'aaa',
        'bbb',
        'ccc'
    ]
    return HttpResponse(json.dumps(user_list))

需要在setting中设置允许的host,否则报错

DisallowedHost at /
Invalid HTTP_HOST header: 'www.s4.com:8001'. You may need to add 'www.s4.com' to ALLOWED_HOSTS.

访问api的网站

这个网站定义成www.s5.com:8000 端口8000,访问s4,使用AJAX的XMLHttpresponse访问是不能获取数据的,同源策略会阻止

def jsonp(request):
    return render(request, 'jsonp.html')

1 使用XMLHttpresponse被拒绝

在s4的网站已经获取到了请求,但是浏览器同源策略禁止接收返回的数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" value="获取用户列表" onclick="getUsers();">
    <ul id="user_list">        
    </ul>
    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function getUsers() {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if(xhr.readyState == 4){
                    var content = xhr.responseText;
                    console.log(content);
                }
            };
            xhr.open('GET','http://www.s4.com:8001/users/');
            xhr.send();
        }
    </script>
</body>
</html>

2 jsonp解决方案

被访问的网站s4

之前返回的数据是[] s5 访问的时候获取到的数据存放在浏览器的内存中,这样就没法获取。最好的方式就是通过变量名获取数据。
这主要返回的数据是带有名字的。下面在s4端对数据进行拼接。

def users(request):
    # v = request.GET.get('callback')
    print('请求is coming')
    user_list = [
        'aaa',
        'bbb',
        'ccc'
    ]
    user_list_str = json.dumps(user_list)
    temp = "a=%s" % (user_list_str)   # 对数据进行拼接
    return HttpResponse(temp)

3 增加灵活性

上面的方式会有变量名重复的问题,而且是全局变量

下面通过get请求的时候直接发送变零名

自己的在get请求中定义vername是aaa,这个是任意的。关键是要和API端相互定义好接口

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" value="获取用户列表" onclick="getUsers();">
    <script>
       function getUsers () {
            var tag = document.createElement('script');
            tag.src = 'http://www.s4.com:8001/users/?varname=aaa'; //自己定义传输的名字
            document.head.appendChild(tag);
       }
    </script>
</body>
</html>

被访问的s4 需要获取get请求中的vername,然后进行拼接。

def users(request):
    # v = request.GET.get('callback')
    v = request.GET.get('varname')  # 获取get请求中的vername
    print('请求is coming')
    user_list = [
        'aaa',
        'bbb',
        'ccc'
    ]
    user_list_str = json.dumps(user_list)
    temp = "%s=%s" % (v,user_list_str)
    return HttpResponse(temp)

4 服务端返回数据的时间是不确定的

上面的已经实现了自己定义返回的数据名,但是服务端返回数据的时间是不确定。特别是返回时间特别长的时候,不能立刻获取数据。

下面在s4服务端进行修改

关键是temp = "%s(%s)" % (v,user_list_str)

返回的数据是aaa()的形式,用户获取数据后,有aaa函数,直接执行aaa函数

def users(request):
    v = request.GET.get('callback')  # 获取callback
    print('请求is coming')
    user_list = [
        'aaa',
        'bbb',
        'ccc'
    ]
    user_list_str = json.dumps(user_list)
    temp = "%s(%s)" % (v,user_list_str)  # 巧妙的方式
    return HttpResponse(temp)

自己的页面

    <script>
       function getUsers () {
            var tag = document.createElement('script');
            tag.src = 'http://www.s4.com:8001/users/?callback=aaa';//aaa是函数名
            document.head.appendChild(tag);
       }
       // 返回数据是aaa()  也就是直接执行下面的函数
       function aaa(arg) {
           console.log(arg)
       }
    </script>

总结:

客户端

  • URL?callback=xxxx
  • function xxxx(arg){}

服务端

  • 获取 funcname = request.GET.get(callback)
  • 返回: funcname(....)

5 使用jQuery的jsonp

上面的方式是我们自己定义并在页面添加了script,jQuery内部也实现了jsonp

加上dataType='JSONP'

 <script src="/static/jquery-3.2.1.js"></script>
    <script>
        $.ajax({
            url:'http://www.s4.com:8001/users/?callback=aaa',
            type:'GET',
            dataType:'JSONP',
            success:function (arg) {
                console.log(arg)
            }
        });
    </script>

6 jsonp 的其他参数

下面的两个参数会自动的在URL上添加成

url:'http://www.s4.com:8001/users/?callback=list'

返回值和函数名是可以修改的,定义成callback和list是一种规范

jsonp:'callback',
jsonpCallback:'list',
  <script src="/static/jquery-3.2.1.js"></script>
    <script>
      function getUsers() {
            $.ajax({
            url:'http://www.s4.com:8001/users/',
            type:'GET', //只能发送get请求 即便是改成post是发个get请求
            dataType:'JSONP',
            jsonp:'callback',
            jsonpCallback:'list',
            success:function (arg) {
                console.log(arg)
            }
        });
      }
    </script>

JSONP总结:

  • 是一种约定
  • 自己写动态添加script
  • 使用jQuery的jsonp
  • jsonp只能发送GET请求
  • jsonp解决的是跨域问题
原文地址:https://www.cnblogs.com/Python666/p/7138534.html