如何使用CORS解决跨域问题

如何使用CORS解决跨域问题

 

一,为什么会有跨域问题

  跨域问题的出现,是因为浏览器的同源策略对ajax请求进行阻拦了,但是并不是所有的请求都给做当做跨域,;像是一般的href属性,a标签什么的都不进行拦截

 

二,什么是同源策略

  同源策略是一种约定,它是浏览器最核心也会是最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

  它约定请求的url地址,必须与浏览器的url地址处于同域上,也就是域名,端口,协议都相同。

  如果不同,就会报错:

已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8001/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。

  实际上的结果是,请求以及被发送过去了,目标服务器也对做出了响应,只是浏览器对非同源请求的放回结果做了拦截。

三,CORS简介

  CORS,跨域资源共享,它需要浏览器和服务器同事支持,目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

  整个CORS通信中,都是浏览器自动完成的,不需要用户的参与,对于开发者来说cors通信与同源的ajax没有差别,代码完全一样。浏览器一旦发现ajax请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有察觉。

  要实现cors通信,主要是在服务器,也就是获得数据的一方做处理。

四,cors基本的流程

  1,浏览器将请求分为两类,一类是简单请求,一类是非简单请求,满足下列条件的就是简单请求,否则即使非简单请求:

复制代码
条件:
    1、请求方式:HEAD、GET、POST
    2、请求头信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 对应的值是以下三个中的任意一个
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
 
注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
复制代码

  2,简单请求和复杂请求的区别:

    简单请求:一次请求

    非简单请求:两次请求,在发送数据之前会先发第一次请求做预检,只有预检通过后在发一次请求作为数据传输。

  3,关于预检:

复制代码
- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
     => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
        Access-Control-Request-Method
     => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
        Access-Control-Request-Headers
复制代码

  4,CORS优缺点

    CORS的优点:可以发任意请求

    CORS的缺点:上是复杂请求的时候得先做一个预检,再发真实的请求,发了两次请求会有性能上的损耗。

五,实现CORS请求

  局部使用:

    简单请求(get)客户端:

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<button id="a" class="btn btn-success">go</button>
<script>
    $("#a").click(function () {
        $.ajax({
            url:'http://127.0.0.1:8000/time/',
            type:'get',
            success:function (data) {
                alert(data)
            }
            }
        )
    })
</script>
</body>
</html>
复制代码

    简单请求服务端:

复制代码
def get_time(request):
    if request.method == 'GET':
        ntime = time.strftime('%Y-%m-%d %X')
        obj = HttpResponse(ntime)
        obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001'
        return obj
复制代码

    复杂请求(post+contentType)客户端:

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<button id="a" class="btn btn-success">go</button>
<script>
    $("#a").click(function () {
        $.ajax({
            url:'http://127.0.0.1:8000/money/',
            type:'post',
            contentType:'application/json',
            data:{"name":"yjh"},
            success:function (data) {
                alert(data)
            }
            }
        )
    })
</script>
</body>
</html>
复制代码

    复杂请求服务端:

复制代码
from django.http import QueryDict
def get_money(request):
    # print(request.body)
    if not request.body:
        obj = HttpResponse('1000000000000')
    else:
        data = request.body # post请求传过来的数据以二进制的形式存放于request.body
        # 将request.body的二进制数据转化为字典形式
        dic = QueryDict(data.decode('utf-8'),encoding='utf-8')
        name = dic.get('name')
        obj = HttpResponse(name)
    if request.method == 'OPTIONS':
        obj['Access-Control-Allow-Headers'] = 'Content-Type'
    obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001'
    return obj
复制代码

六:全局配置

  由于是全局配置,所以应该写在中间件中。然而,我们知道浏览器是在返回的时候出现的禁用,因此我们我们需要重写process_response方法。

  第一步:在应用文件夹根目录中,新建一个my_middleware.py文件

  第二步:在该py文件夹中写上:

复制代码
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
    def process_response(self,request,response):
        if request.method=="OPTIONS":
            #可以加*
            response["Access-Control-Allow-Headers"]="Content-Type"
        response["Access-Control-Allow-Origin"] = "http://localhost:8080"
        return response
复制代码

  第三步:在settings.py中配置:

复制代码
MIDDLEWARE = [
    'app01.my_middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
复制代码
posted @ 2019-10-31 15:51  zy740  阅读(554)  评论(0编辑  收藏  举报