jsonp

项目讲完了,但要及时的复习

今天就来讲一下jsonp,

先来说一下同源策略。

同源策略

一个源的定义:如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的

一般的http协议会走默认的走80端口,https默认走443端口。域名会翻译成ip地址。

举个例子:

下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例:

URL结果原因
http://a.xyz.com/dir2/other.html 成功  
http://a.xyz.com/dir/inner/another.html 成功  
https://a.xyz.com/secure.html 失败 不同协议 ( https和http )
http://a.xyz.com:81/dir/etc.html 失败 不同端口 ( 81和80)
     

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以xyz.com下的js脚本采用ajax读取abc.com里面的文件数据是会被拒绝的。

意思就是当我们在访问两个网页时,这两个网页之间的文件数据是不能互相读取的。

比如说我们在这个页面发送一个Ajax请求去请求另外一

不受同源策略限制的:

1. 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。

2. 跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。

举个例子

我们手写两个Django demo:

demo1:(端口设为8000)

url.py

from app01 import views

urlpatterns = [
    url(r'^abc/', views.abc),
]

view.py

def abc(request):return HttpResponse('alex')

demo2:(端口设为8005)

url.py

from app02 import views

urlpatterns = [
    url(r'^xyz/', views.xyz),
]

views.py

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

xyz.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button type="button" id="btn">点我</button>
<script>
$('#btn').click(function () {
$.ajax({
url:'http://127.0.0.1:8000/',
type:'get',
success:function (res) {
console.log(res)
}
})
})
</script> {#<script src="http://127.0.0.1:8000/abc/"></script>#} <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> 
</body>
</html>

现在,打开使用浏览器打开http://127.0.0.1:8000/xyz/,点击页面上的 '点我' 按钮,会在console页面发现错误信息如下:

为什么报错呢?因为同源策略限制跨域发送ajax请求。

细心点的同学应该会发现我们的demo1项目其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。

但是我们在页面中的script标签中写入src的cdn方式就可以跨域请求,这就是一个漏洞,我们可以利用这点来搞些事情。我们可以不用在demo2进行点击事件,可以这样

<script src="http://127.0.0.1:8000/abc"></script>

这样就会出现这样的报错。

说是alex没有定义。我们在上面定义一个alex,就不会报错了,var alex = ‘sb’,既然定义一个变量可以,那么定义一个函数名叫alex同样也是可以的,在demo1返回一个alex(),就可以执行demo2中的这个函数。

 //回调函数
function alex() { console.log(‘我是大帅逼’) }

这样就可以实现跨域请求了。

既然可以执行函数,那么当然可以加参数了。在demo1试图函数中添加一个参函数。(因为添加的是一个字典,所以要导入json进行序列化)

def abc(request):
    res = {'code':0,'data':[0,1,2,3]}
    data_str = json.dumps(res)
    return HttpResponse('alex({})'.format(data_str))

在demo2中就在函数中加一个参数(也要注意函数要定义在script标签之前,不然会报alex为定义的错误。)

//回调函数
function alex(res) { console.log(res) }

这就实现了在demo2的端口拿到了demo1端口的数据。

 现在是页面刷新就发送请求,那么怎么实现点击之后在发送请求呢?我们有这样一个思路就是在我们点击按钮时,插入一个script标签。

$('#btn').click(function(){
    var scriptEle = document.createElement('script')    // 创建标签
    $(scriptEle).attr('src','http://127.0.0.1:8000/abc')  //添加属性
    $('body').append(scriptEle)                               //将script标签添加到body
    $(scriptEle).remove()                                      //发送请求后删除
}

 这样同样可以拿到另一个页面的数据,这其实就是jsonp的原理。利用script标签绕过同源策略的限制,拿到数据。

那么当demo1中有两个试图函数呢?我们怎么实现去访问这两个试图的数据。这当然是写两个点击事件呗。

  function addscriptag(url) {
        var scriptEle = document.createElement('script');
        $(scriptEle).attr('src',url);
        $('body').append(scriptEle);
        $(scriptEle).remove();
    }
    $('#btn').click(function () {
        addscriptag('http://127.0.0.1:8000/abc/')
    });
    $('#btn2').click(function () {
        addscriptag('http://127.0.0.1:8000/cba/')
    });

这里是将创建script标签写成了函数。这样就能获取到两个视图函数的数据了。

那我这样写:

demo2中的script标签:

 function addscriptag(url) {
        var scriptEle = document.createElement('script');
        $(scriptEle).attr('src',url);
        $('body').append(scriptEle);
        $(scriptEle).remove();
    }
    $('#btn').click(function () {
        addscriptag('http://127.0.0.1:8000/abc/?func=alex')
    });
    $('#btn2').click(function () {
        addscriptag('http://127.0.0.1:8000/cba/?func=yangbo')
    });

这个代码也可以这样写:
function addscriptag(url,func) {
        var scriptEle = document.createElement('script');
        $(scriptEle).attr('src',url + '?func=' + func);
        $('body').append(scriptEle);
        $(scriptEle).remove();
    }
    $('#btn').click(function () {
        addscriptag('http://127.0.0.1:8000/abc/','alex')
    });
    $('#btn2').click(function () {
        addscriptag('http://127.0.0.1:8000/cba/','yangbo')
    });
 

demo1中的视图函数:

def abc(request):
    func = request.GET.get('func')
    res = {'code':0,'data':[0,1,2,3]}
    data_str = json.dumps(res)
    return HttpResponse('{}({})'.format(func,data_str))

def cba(request):
    func = request.GET.get('func')
    res = {'name':'alex','age':20}
    data_str = json.dumps(res)
    return HttpResponse('{}({})'.format(func,data_str))

当我们点击btn的时候,走的是http://127.0.0.1:8000/abc/?func=alex地址,在demo1的abc视图函数中,get取到func的值,作为参数,并且和数据一起返回,点击btn2的时候同理。

这样我们就实现了地址的动态变化,只需要你改func后面的内容,就能拿到不同视图函数中的数据。

但是这样写还是很麻烦。

jQuery中getJSON方法

demo2中的js代码:

$('#btn').click(function () {
        $.getJSON('http://127.0.0.1:8000/abc/?callback=?',function (res) {
            console.log(res)
        })
    })

demo1的视图函数:

def abc(request):
    func = request.GET.get('callback')
    res = {'code':0,'data':[0,1,2,3]}
    data_str = json.dumps(res)
    return HttpResponse('{}({})'.format(func,data_str))

这样是不是就是很简单。格式比较固定都不需用写回调函数。callback后面的那个?是jQuery内部自动生成的一个回调函数名。

但是如果我们就想实现执行我们自定义的回调函数名,就要用到ajax。

 //回调函数
 function yangbo(res) {
        $.each(res,function (k,v) {
            console.log(k,v)
        })
    }

  $('#btn').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8000/abc',
            dataType:'jsonp', //此次请求是jsonp格式
            jsonp:'callback',  //回调函数url的参数名
            jsonpCallback:'yangbo'  // 回调函数
        })
    })

那能不能再优化一下呢?

  $('#btn').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8000/abc',
            dataType:'jsonp',
            success:function (res) {
                console.log(res)
            }
        })
    })

JSONP应用:

$('#btn').click(function () {
        $.ajax({
            url:'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403',
            dataType:'jsonp',
       jsonp:'callback' jsonpCallback:
'list', success:function (res) { console.log(res)
         console.log(res.data)
          接下来就进行一些dom操作
} })

有几个关键点:回调函数和回调函数url的参数名。

老师完整代码:

// 跨域请求示例
$("#show-tv").click(function () {
  $.ajax({
    url: "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403",
    dataType: 'jsonp',
    jsonp: 'callback',
    jsonpCallback: 'list',
    success: function (data) {
      var weekList = data.data;
      var $tvListEle = $(".tv-list");
      $.each(weekList, function (k, v) {
        var s1 = "<p>" + v.week + "列表</p>";
        $tvListEle.append(s1);
        $.each(v.list, function (k2, v2) {
          var s2 = "<p><a href='" + v2.link + "'>" + v2.name + "</a></p>";
          $tvListEle.append(s2)
        });
        $tvListEle.append("<hr>");
      })
    }
  })
});
原文地址:https://www.cnblogs.com/yb635238477/p/9520713.html