Django跨域请求--CORS

在上一篇文章中DJANGO跨域请求--JSONP已经阐述了为什么我们需要跨域请求,以及跨域方法JSONP。随着技术的发展,现在的浏览器可以主动支持设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

一 CORS基础

1.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
 
注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求

1.2 简单请求与复杂请求的区别

简单请求:一次请求

复杂请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。

1.3 关于预检

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

1.4 CORS简图

image_thumb1

1.5 CORS的优缺点

优点:可以发任意请求

缺点:复杂请求时得先做个“预检”,再发真实的请求,两次请求会有性能上的损耗

二 基于CORS实现AJAX请求

2.1 支持跨域,简单请求

服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

客户端cors.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>CORS示例</h3>
    <button type="button" onclick="getData()" >获取第三方数据</button>

    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function getData() {
            $.ajax({
                url:'http://127.0.0.1:8000/cors_data/',
                type:'GET',
                success:function (arg) {
                    var $tag = $('<h6>');
                    $tag.text(arg);
                    $('h3').append($tag);
                }
            })
        }
    </script>
</body>
</html>

第三方服务端views.py

def cors_data(request):
    obj = HttpResponse('第三方数据')
    obj['Access-Control-Allow-Origin'] = "http://127.0.0.1:8001"
    return obj

如果我们对所有的地址都不进行限制,第三方服务端views.py中为:

obj['Access-Control-Allow-Origin'] = "*"

执行结果:

image_thumb3

2.2 支持跨域,复杂请求

复杂请求在发送真正的请求前,会先发送一个OPTIONS请求,第三方服务端先”预检“一下,”预检“通过才会发送正式数据。

  • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
  • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
  • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age

方式一:请求方式类复杂请求

客户端cors.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>CORS示例</h3>
    <button type="button" onclick="getData()" >获取第三方数据</button>

    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function getData() {
            $.ajax({
                url:'http://127.0.0.1:8000/cors_data/',
                //type:'GET',
                type:'PUT',   //方式为PUT,为复杂请求
                success:function (arg) {
                    var $tag = $('<h6>');
                    $tag.text(arg);
                    $('h3').append($tag);
                }
            })
        }
    </script>
</body>
</html>
访问结果:
image_thumb5

image_thumb7

这里因为为复杂请求,我们需要在后端代码增加一个预检的过程。

第三方服务端views.py

def cors_data(request):
    if request.method == 'OPTIONS':
        # 预检
        obj = HttpResponse()
        obj['Access-Control-Allow-Origin'] = " http://127.0.0.1:8001"
        obj['Access-Control-Allow-Methods'] = "PUT"  #需要设置
        return obj
    elif request.method == "PUT":
        obj = HttpResponse('第三方数据')
        obj['Access-Control-Allow-Origin'] = " http://127.0.0.1:8001"
        return obj

执行结果:

image_thumb10

注意:测试时需要注释掉第三方settings.py中的CSRF

方式二:带有请求头的复杂请求

客户端cors.html中js代码更改如下:

<script>
	function getData() {
		$.ajax({
			url:'http://127.0.0.1:8000/cors_data/',
			type:'GET',
			headers:{'name':'joe1991'},   //有请求头的复杂请求
			success:function (arg) {
				var $tag = $('<h6>');
				$tag.text(arg);
				$('h3').append($tag);
			}
		})
	}
</script>		

第三方服务端views.py

def cors_data(request):
    if request.method == 'OPTIONS':
        # 预检
        obj = HttpResponse()
        obj['Access-Control-Allow-Origin'] = " http://127.0.0.1:8001"
        obj['Access-Control-Allow-Headers'] = 'name'    #处理方式不同
        # obj['Access-Control-Allow-Methods'] = "PUT"
        return obj
    else :
        obj = HttpResponse('第三方数据')
        obj['Access-Control-Allow-Origin'] = " http://127.0.0.1:8001"
        return obj

前端访问截图

image_thumb12

2.3 跨域获取响应头及跨域传输cookie

请参考:http://www.cnblogs.com/wupeiqi/articles/5703697.html

三 JSONP与CORS的区别简析

JSONP:主要修改在前端部分,后端需做约束修改,发jsonp请求

JSONP:只能发GET请求

CORS:前端的代码不用修改,服务端的代码需要修改

CORS:可以发任意请求,简单请求与复杂请求处理方式不同

 

优秀文章推荐:http://www.ruanyifeng.com/blog/2016/04/cors.html

posted @ 2018-11-06 15:28  Joe1991  阅读(150)  评论(0)    收藏  举报