【转】同源策略和跨域请求解决方案

一、一个源的定义

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

      下表给出了相对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)
      http://a.opq.com/dir/other.html             失败    不同域名 ( xyz和opq)

二、同源策略是什么?

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

同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

三、基于jsonp实现的跨域请求

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

下面来分步举例详细阐述其中的奥妙:

1、先开两个项目,

项目1(http://127.0.0.1:8000/)
项目2(http://127.0.0.1:8100/)

项目1

url:
url(r‘index1/$‘,views.index1)

views:

def index1(request):
return  HttpResponse(‘wangjifei‘)

项目2

url:
url(r‘index2/$‘,views.index2)

views  :
def index2(request):
    return render(request,‘index2.html‘)

index2.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>
    $(‘#btn‘).click(function () {
        $.ajax({
            url:"http://127.0.0.1:8000/index1/",
            type:‘get‘,
            success:function (res) {
                console.log(res)
           }
        })
    })
</script>
</body>
</html>

现在,打开使用浏览器打开 http://127.0.0.1:8100/index2/,点击页面上的 ‘提交‘ 按钮,会在console页面发现错误信息如下:

为什么报错呢?因为同源策略限制跨域发送ajax请求。
细心点的同学应该会发现我们的demo1项目其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。
再细心点的同学会发现,我们使用cdn方式引用的jQuery文件也是跨域的,它就可以使用。
同样是从其他的站点拿东西,script标签就可以。那我们能不能利用这一点搞点事情呢?

2、把index2.html中的代码改一下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

现在刷新一下会出现如下错误:

看来后端返回的响应已经被拿到了,只不过把wangjifei当成了一个变量来使用,但是该页面上却没有定义一个名为wangjifei的变量。所以出错了。

3、那我们就在index2.html中定义一个wangjifei变量看看:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script>
    var wangjifei = 123
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

刷新发现不报错了,

4、我定义一个变量可以,那可不可以定义一个函数呢?

index2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script>
    function wangjifei() {
        console.log(‘出手就要专业‘)
    }
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

项目1中的views:也修改一下

def index1(request):
return  HttpResponse(‘wangjifei()‘)

刷新一下页面显示结果:

结果分析:返回的 wangjifei(),页面上拿到这个响应之后直接执行了wangjifei函数!

5、那函数中可不可以传递参数呢?我们试一下!

index2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script>
    function wangjifei(res) {
         console.log(res)
    }
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

项目1中的 views

from django.http import HttpResponse
import json

def index1(request):
    ret={‘code‘:1,‘msg‘:[110,119,120,12306]}
    res = json.dumps(ret)
    return  HttpResponse(f‘wangjifei({res})‘)

刷新之后显示结果:

果然传递参数也是可以的!我们通过script标签的跨域特性来绕过同源策略拿到想要的数据了!!!

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。
但是我们更多时候是希望通过事件触发数据的获取,而不是像上面一样页面一刷新就执行了,这样很不灵活。

6、我们可以通过javascript动态的创建script标签来实现。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>
    //自定义的函数
    function wangjifei(res) {
        console.log(res)
    }
    //jquery给button绑定点击事件
    $(‘#btn‘).click(function () {
        //创建一个script标签
        var scriptEle = document.createElement(‘script‘);
        //给标签添加src属性,并添加对应的属性值    http://127.0.0.1:8000/index1
        $(scriptEle).attr(‘src‘,‘http://127.0.0.1:8000/index1‘);
        //将创建好的标签添加到页面中,标签添加后就会自动触发get请求
        $(‘body‘).append(scriptEle);
        //将标签移除
        $(scriptEle).remove()
    })
</script>
</body>
</html>

这样当我们点击button按钮的时候,会在页面上插入一个script标签,然后从后端获取数据后再删除掉。

7、为了实现更加灵活的调用,我们可以把客户端定义的回调函数的函数名传给服务端,服务端则会返回以该回调函数名,将获取的json数据传入这个函数完成回调。这样就能实现动态的调用了。修改代码如下:

index2.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>

<button id="btn">提交</button>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>
    //自定义的函数
    function xxx(res) {
        console.log(res)
    }
    //jquery给button绑定点击事件
    $(‘#btn‘).click(function () {
        //创建一个script标签
        var scriptEle = document.createElement(‘script‘);
        //给标签添加src属性,并添加对应的属性值    http://127.0.0.1:8000/index1?callback=xxx
        $(scriptEle).attr(‘src‘,‘http://127.0.0.1:8000/index1?callback=xxx‘);
        //将创建好的标签添加到页面中,标签添加后就会自动触发get请求
        $(‘body‘).append(scriptEle);
        //将标签移除
        $(scriptEle).remove()
    })
</script>
</body>
</html>

项目1中views:

from django.http import HttpResponse
import json

def index1(request):
    ret={‘code‘:1,‘msg‘:[110,119,120,12306]}
    res = json.dumps(ret)
    callback = request.GET.get(‘callback‘)
    return  HttpResponse(f‘{callback}({res})‘)

四、jQuery中getJSON方法介绍:

1、jQuery中有专门的方法实现jsonp。

index2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>
<button id="btn">提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">        </script>
<script>
    //jquery给button绑定点击事件
    $(‘#btn‘).click(function () {
        $.getJSON("http://127.0.0.1:8000/index1?callback=?",function (res) {
            console.log(res)
        })
    })
</script>
</body>
</html>

要注意的是在url的后面必须要有一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个?是jQuery内部自动生成的一个回调函数名。

2、但是如果我们想自己指定回调函数名,或者说服务上规定了回调函数名该怎么办呢?我们可以使用$.ajax方法来实现:

index2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>
<button id="btn">提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>
    //jquery给button绑定点击事件
    $(‘#btn‘).click(function () {
        $.ajax({
            //要访问的url
            url:"http://127.0.0.1:8000/index1/",
            //要处理的数据类型jsonp
            dataType:‘jsonp‘,
            //自定义回调函数名必要参数
            jsonp:‘callback‘,
            //自定义回调函数名,url中callback=后面的函数名
            jsonpcallback:‘wangjifei‘
        })
    });
    //回调函数
    function wangjifei(res) {
        console.log(res)
    }
</script>
</body>
</html>

views:

from django.http import HttpResponse
import json

def index1(request):
    ret={‘code‘:1,‘msg‘:[110,119,120,12306]}
    res = json.dumps(ret)
    callback = request.GET.get(‘callback‘)
    return  HttpResponse(f‘wangjifei({res})‘)

3、用ajax技术通常将回调函数写在成功回调函数的位置:

index2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>
<button id="btn">提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>
    //jquery给button绑定点击事件
    $(‘#btn‘).click(function () {
        $.ajax({
            //要访问的url
            url:"http://127.0.0.1:8000/index1/",
            //要处理的数据类型jsonp
            dataType:‘jsonp‘,
            //success回调
            success:function (res) {
                console.log(res)
            }
        })
    });
    //回调函数
    function wangjifei(res) {
        console.log(res)
    }
</script>
</body>
</html>

最后来一个jsonp的实际应用:

 <!DOCTYPE html>
     <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>同源策略</title>
    </head>
    <body>
    <button id="show-tv">提交</button>
    <div class="tv-list"></div>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        $("#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;
                    console.log(weekList);
                    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>");
                    })
                }
            })
        });
    </script>
    </body>
    </html>

五、基于Core方法解决跨域请求

  • 我们介绍了jsonp解决跨域请求问题,这种解决方式很好的诠释了跨域请求的本质,但是略显麻烦,是否还记得在我们不做任何处理的时候,跨域请求时候浏览器给我们报的错误不?翻译过来就是因为响应头没有指定Access-Control-Allow-Origin所允许原始的请求路径,因此原始请求路径http://127.0.0.1:8001不被允许访问。 基于上述的原因解释,我们只需要在响应的内容加入上述这样的授权字段,便可解决。
  • 简单请求的定义:
    只要同时满足以下两大条件,就属于简单请求,不满足就是复杂请求!!!
    1.(1) 请求方法是以下三种方法之一:
    -- HEAD,GET,POST
    2.(2)HTTP的头信息不超出以下几种字段:
    -- Accept
    -- Accept-Language
    -- Content-Language
    -- Last-Event-ID
    -- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

由于django的所有请求响应都要走中间件,所以可以写一个跨域的中间件来解决跨域问题

from django.utils.deprecation import MiddlewareMixin
class MyCore(MiddlewareMixin):
    def process_response(self, request, response):
        response[‘Access-Control-Allow-Origin‘] = "*"  //简单请求
        if request.method == "OPTIONS":
            # 复杂请求 预检
            response[‘Access-Control-Allow-Headers‘] = "Content-Type"
            response[‘Access-Control-Allow-Methods‘] = "POST, DELETE, PUT"
        return response

原文出处:https://www.jianshu.com/p/bce07495b77c

原文地址:https://www.cnblogs.com/sanxiao/p/11604442.html

时间: 2024-10-13 03:29:43

【转】同源策略和跨域请求解决方案的相关文章

4.同源策略与跨域请求

一.同源策略基本概念 1.同源策略概念: 一种约定,它是浏览器最核心也是最基本的安全功能,同源指域名.协议.端口需要保持一直才能进行相互间的访问. 2.例子: (1)http://a.com没有办法访问到http://b.com下的脚本文件和文档. (2)浏览器采用同源策略,禁止页面加载或执行与自身那个来源不同的域的任何脚本.换句话说浏览器禁止的是来源不同的“document”或脚本用来对当前“document”读取或设置某些属性. (3)哪些不受同源限制 <script>.<img&g

同源策略和跨域解决方案

同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对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 ) h

浏览器的同源策略及跨域解决方案

同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对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 ) h

解说同源策略和跨域访问

尽管浏览器的安全措施多种多样,但是要想黑掉一个Web应用,只要在浏览器的多种安全措施中找到某种措施的一个漏洞或者绕过一种安全措施的方法即可.浏览器的各种保安措施之间都试图保持相互独立,但是攻击者只要能在出错的地方注入少许JavaScript,所有安全控制几乎全部瓦解--最后还起作用的就是最弱的安全防线:同源策略.同源策略管辖着所有保安措施,然而,由于浏览器及其插件,诸如Acrobat Reader.Flash 和Outlook Express漏洞频出,致使同源策略也频频告破. 既然web应用的最

浏览器的同源策略和跨域访问

1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略.    何谓同源:        URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.    同源策略:        浏览器的同源策略,限制了来自不同源的"document"或脚本,对当前"document"读取或设置某些属性.        从一个域上加载的脚本不允许访问另外一个域的文档属性. 举个例子:      

11. cookie_session_原生ajax_readyState的值_同源策略_跨域_jsonp的使用

1. cookie 浏览器存储技术.(服务器将少量数据交于浏览器存储管理) 作用: 存储数据, 解决 http 协议无状态问题 工作流程: 浏览器发送请求给服务器,请求登录 服务器返回响应给浏览器,此时携带了cookie(其中包含着当前用户的唯一标识) 浏览器接受到响应中cookie,得保存下来 浏览器下一次发送请求时,会自动携带上cookie, 服务器接受到请求,解析cookie,从而判断是哪个用户发送的请求(解决http协议无状态问题) 服务器端的使用: 设置cookie        re

同源策略和跨域-总结

目录: 1.同源策略 2.跨域 3.几种跨域技术 1.同源策略 什么叫同源? URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域. e.g. 对于http://store.company.com/dir/page.html进行同源检测: URL 结果 原因 http://store.company.com/dir2/other.html 成功 仅路径不同 http://store.company.c

JS同源策略和跨域访问

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现. 1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略. 何谓同源: URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源. 同源策略: 浏览器的同源策略,限制了来自不同源的"doc

同源策略和跨域访问

1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略.     何谓同源:         URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.     同源策略:         浏览器的同源策略,限制了来自不同源的"document"或脚本,对当前"document"读取或设置某些属性. (白帽子讲web安全[1])         从一个域上加载的脚本不允许访问另外一