何谓同源策略与Jsonp

版权声明:如需发表此文章,请附带转载标志或原地址链接,谢谢合作 https://blog.csdn.net/weixin_38091140/article/details/89003228

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。

1、先来说说什么是源


• 源(origin)就是指的协议、域名和端口号。
以上url中的源就是:http://www.company.com:80
若地址里面的协议、域名和端口号均相同则属于同源。
以下是相对于 http://www.a.com/test/index.html 的同源检测
• http://www.a.com/dir/page.html ----成功
• http://www.child.a.com/test/index.html ----失败,域名不同
• https://www.a.com/test/index.html ----失败,协议不同
• http://www.a.com:8080/test/index.html ----失败,端口号不同

2.什么是同源策略?


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

• 不受同源策略限制的:
1、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
2、跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。

二、跨域  


1、什么是跨域


受前面所讲的浏览器同源策略的影响,不是同源的脚本不能操作其他源下面的对象。想要操作另一个源下的对象是就需要跨域。

2、跨域的实现形式


• 降域 document.domain
同源策略认为域和子域属于不同的域,如:
child1.a.com 与 a.com,
child1.a.com 与 child2.a.com,
xxx.child1.a.com 与 child1.a.com
两两不同源,可以通过设置 document.damain='a.com',浏览器就会认为它们都是同一个源。想要实现以上任意两个页面之间的通信,两个页面必须都设置documen.damain='a.com'。
此方式的特点:
1. 只能在父域名与子域名之间使用,且将 xxx.child1.a.com域名设置为a.com后,不能再设置成child1.a.com。
2. 存在安全性问题,当一个站点被攻击后,另一个站点会引起安全漏洞。
3. 这种方法只适用于 Cookie 和 iframe 窗口。
• JSONP跨域
JSONP和JSON并没有什么关系!
JSONP的原理:(举例: http://127.0.0.1:8001/想得到 http://127.0.0.1:8002/中的数据)在a.com的jsonp.html里创建一个回调函数xxx,动态添加<script>元素,向服务器发送请求,请求地址后面加上查询字符串,通过callback参数指定回调函数的名字。请求地址为 http://127.0.0.1:8001?callback=xxx。在main.js中调用这个回调函数xxx,并且以JSON数据形式作为参数传递,完成回调。

现在我们看看 http://127.0.0.1:8001/的html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<p>这是首页!</p>
<button>提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
    $("button").click(function () {
        alert(123)
        $.ajax({
            url: "http://127.0.0.1:8002//test/",
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</body>
</html>

在这个代码里面调用了8002的资源。

8802:的views代码:

from django.shortcuts import render, HttpResponse

# Create your views here.


def test(request):
    print("会出现吗。很是期待哦")

    return HttpResponse("this is test")

这是一个简单的调用。你会发现。浏览器不允许你进行调用。

因为控制台已经给你调用了

说明是浏览器不允许你进行跨域.

但是你们发现没有。同样是跨域调用。我进行jquery的cdn调用就不会进行拦截。

看到这里你的心里难道就没有点想法吗?

没有,既然不给我进行js的跨域,那我跨域伪装成上面的那种方式进行调用呀!说干就干,撸起手就是干。

8001的HTML代码如图:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<p>这是首页!</p>
{#{% csrf_token %}#}
<button>提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$("button").click(function () {

        var html_script = $("<script>");
        html_script.attr("src","http://127.0.0.1:8002/test/");
        html_script.attr("id","test");
        $("body").append(html_script);
        $("#test").remove();//生成的标签调用完毕,马上移除掉。
})
    function get_data(test2_data) {
        console.log(test2_data)
    }
</script>
</body>
</html>

8002 的views代码:

from django.shortcuts import render, HttpResponse

# Create your views here.


def test(request):
    print("会出现吗。很是期待哦")
    return HttpResponse("get_data('ok')")  # 传递一个跟8001同名的get_data()函数

这样调用跨域的资源就不会出错了。

。现在为了更加灵活,现在将在客户端定义的回调函数传送给服务端。服务端就会返回逸直接定义的回调函数名的方法。将获取的json数据传入这个方法就可以完成回调了。

8001代码也就是客户端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<p>这是首页!</p>
{#{% csrf_token %}#}
<button>提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$("button").click(function () {

        var html_script = $("<script>");
        html_script.attr("src","http://127.0.0.1:8002/test/?callbacks=get_data");
        html_script.attr("id","test");
        $("body").append(html_script);
        $("#test").remove();//生成的标签调用完毕,马上移除掉。
})
    function get_data(test2_data) {
        console.log(test2_data)
    }
</script>
</body>
</html>

8002也就是服务端只需这样调用即可:

from django.shortcuts import render, HttpResponse
import json

# Create your views here.


def test(request):
    print("会出现吗。很是期待哦")
    func = request.GET.get("callbacks")
    print(func)
    a_dict = {"key": "values"}
    return HttpResponse("%s(%s)" % (func, json.dumps(a_dict)))  # 需要把数据进行序列化方可以传递过去

让我们来看看结果呗

这就跨域调用数据成功了。

jQuery中的Jsonp方法

只需要改动8001中的html代码即可:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<p>这是首页!</p>
{#{% csrf_token %}#}
<button>提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$("button").click(function () {
    f("http://127.0.0.1:8002/test/")
})
 function f(url) {
     $.ajax({
         url: url,
         dataType:"jsonp",
         jsonp: 'callbacks', //这里的值(callbacks)相当于url中的建的名字
         jsonpCallback: 'ok', // 这里的值(ok)相当于回调函数的函数名,也就是url中的值
         success:function (data) {
             console.log(data)
         }
     });
 }
</script>
</body>
</html>

你可以正常的跨域调用。

但是上面的代码有个可以不用有:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<p>这是首页!</p>
{#{% csrf_token %}#}
<button>提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$("button").click(function () {
    f("http://127.0.0.1:8002/test/")
})
 function f(url) {
     $.ajax({
         url: url,
         dataType:"jsonp",
         jsonp: 'callbacks', //这里的值(callbacks)相当于url中的建的名字
         //jsonpCallback: 'ok', // 这里的值(ok)相当于回调函数的函数名,也就是url中的值
         success:function (data) {
             console.log(data)
         }
     });
 }
</script>
</body>
</html>

从这里可以看出不一定需要自己定义回调函数名也可以,jsonp也可以帮你生成函数名:

通过CORS实现跨域调用。

猜你喜欢

转载自blog.csdn.net/weixin_38091140/article/details/89003228