Django开发遇到的跨域问题(CORS跨域资源共享)

一、同源策略:

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

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

当发起的请求的域与该请求指向的资源所在的域的ip+端口及协议一致时,认为是同一个源。

 不同源的域之间数据交互,会被浏览器拦截,但是其实我们要访问的地址已经拿到数据并返回了,只是浏览器给拦截了

二、什么是跨域?

当前发起的请求的域与该请求指向的资源所在的域不一致。当协议+域名+端口号均相同,那么就是同一个域。举个例子,http://www.xxx.com发起了一个get请求,请求的地址是:http://www.xxx.com/getuserlist?u=test,这里就不存在跨域请求的问题。由于跨域请求存在诸多安全问题,例如CSRF攻击等,所以我们的浏览器针对这个安全问题会有一个同源策略,必须是我们上面说到的同源请求,才能顺利发出请求。

通常情况下,A网页访问B服务器资源时,不满足以下三个条件其一就是跨域访问
        1. 协议不同
        2. 端口不同
        3. 主机不同

三、解决方案:

方案一:

安装django-cors-headers模块

在settings.py中配置
# 注册app
INSTALLED_APPS = [
    ...
    'corsheaders'
]
# 添加中间件
MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware'
]
# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True

 方案二(CORS):

CORS(跨域资源共享):

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

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

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

 CORS基本流程:

浏览器将CORS请求分成两类:

  •         简单请求(simple request)
  •         非简单请求(not-so-simple request)

浏览器发出CORS简单请求,只需要在头信息之中增加一个Origin字段。
浏览器发出CORS非简单请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

 两种请求方法详解:

只要同时满足以下两大条件,就属于简单请求:

"""
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
"""

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

"""
* 简单请求和非简单请求的区别?
   简单请求:一次请求
   非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。

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

具体使用:

我在8000端口启动一个项目向8001端口发送请求,结果发现:

 这个就是简单请求,只需改一下视图函数即可。

127.0.0.1:8001的视图

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
class PublishView(APIView):
    def get(self, request, *args, **kwargs):
        obj = HttpResponse('8000端口来的请求')
        obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
        return obj

127.0.0.1:8000的视图

from django.shortcuts import render
def index(request):
    return render(request, 'index.html')

index.html

<button id="id_button">点我</button>
<script>
    $('#id_button').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/publish/',
            type:'get',
            success:function (data) {
                console.log(data)
            }
        })
    })
</script>

处理非简单请求和简单请求:

这个需要在中间件完成,我们需要自定义一个中间件。

因为是8000向8001请求,8001返回,所以要在8001的域自定义中间件。

然后要在配置文件中注册,一定要放在第一位

from django.middleware.security import SecurityMiddleware
from django.utils.deprecation import MiddlewareMixin
class MyCorsMiddle(MiddlewareMixin):
    def process_response(self, request, response):
        if request.method == 'OPTIONS':
            # 允许Content-Type类型
            response['Access-Control-Allow-Headers'] = 'Content-Type'
            # 允许所有的header
            # obj['Access-Control-Allow-Headers']='*'
            # 允许某个ip+port
            # obj['Access-Control-Allow-Origin']='http://127.0.0.1:8000'
        response['Access-Control-Allow-Origin'] = '*'
        return response

然后再写一个视图测一下:

def index(request):
    import json
    obj = HttpResponse(json.dumps({'msg': 'okok'}))
    return obj

再看8000端口的视图:

from django.shortcuts import render
def index(request):
    return render(request, 'index.html')

index.html

测试发现8000端口的网页收到并打印了数据 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值