zoukankan      html  css  js  c++  java
  • Django中的跨域问题

    一.跨域的实质

    服务器的跨域问题,在于如果进行前后端分离的网站开发时,前端与后端的域名、协议、端口不一致,导致浏览器进行的服务请求拦截。但其实虽然说浏览器将请求拦截下来,但是请求依然是请求成功,只不过服务器没有将数据在网页中进行渲染。

    跨域,其实也叫同源策略。

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

    同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。

    如果说一旦浏览器发现请求的服务器与发起请求的服务器不是同源, 则会主动进行拦截,为了保证服务器的数据安全。

    如果说现有两个Django项目,项目2向项目1的服务器请求数据,那么一旦发起了这次请求,请求是成功的,数据也会得到,但是浏览器在渲染的时候会进行拦截报错:

    
    已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:7766/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
    这是火狐浏览器中的错误提示,谷歌浏览器错误提示相同,只不过是英文的
    

    针对跨域请求问题,如果使用Django开发网站,根据请求的类型不同,有不同的处理方法。

    二.CORS

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

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

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

    CORS的两种请求

    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

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

    而简单请求需要同时满足以下两种条件:

    (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
    

    而只要不满足上述的两种条件,那就是复杂请求。

    CORS针对简单请求和复杂请求,进行处理请求跨域的方式是不一样的

    针对简单请求处理请求跨域

    简单请求进行跨域请求,如果不进行跨域的处理,那么浏览器的报错信息是:

    Access to XMLHttpRequest at 'http://127.0.0.1:8008/books/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    

    其实就是服务器进行响应的时候,缺少一个响应头:Access-Control-Allow-Origin,只需要在 响应给浏览器时,将这个响应头加上即可:

    from django.http import JsonResponse
    def books(request):
        print("s2 books")
        obj = JsonResponse(["python", 'linux', "go"], safe=False)
        obj["Access-Control-Allow-Origin"] = "*"
        return obj
    

    添加响应头时,右侧的*,代表任何请求,不管是从哪个域名向服务器发起的请求,都予以通过。当然,也可以专门设置某一个域名的跨域请求通过:

    obj["Access-Control-Allow-Origin"] = "192.168.0.1:8000"
    这表明只有从IP是192.168.0.1,且端口是8000的服务器发来的请求,能够成功访问。
    

    如果是想要在一个Django项目中的每个视图函数,都进行跨域的处理,那我们可以直接添加一个中间件来专门处理跨域请求。

    注意:中间件是要处理服务器给出响应,所以要重写process_response方法:

    class MyMiddle(MiddlewareMixin):
        def process_response(self, request, response):
            response["Access-Control-Allow-Origin"] = "*"
            return response
    
    针对复杂请求处理请求跨域

    复杂请求,例如浏览器向服务器发送DELETEPUT等请求时,那么浏览器会向服务器发送一个预检请求,来询问服务器的跨源策略,如果配置符合,则继续发送请求,否则就会抛出错误。

    而浏览器发送的预检请求,一般都是OPTIONS类型的请求。

    此时,我们需要在服务器的响应中,再设置一个头信息:Access-Control-Allow-Origin,即可完成预检请求,实现跨域。

    from django.http import JsonResponse
    def books(request):
        print("s2 books")
        obj = JsonResponse(["python", 'linux', "go"], safe=False)
        obj["Access-Control-Allow-Headers"]="Content-Type,b"
        obj["Access-Control-Allow-Origin"] = "*"
        return obj
    

    同样的,我们 可以用中间件来实现简单请求和复杂请求的跨域请求:

    class MyMiddle(MiddlewareMixin):
        def process_response(self, request, response):
            response["Access-Control-Allow-Origin"] = "*"
            response["Access-Control-Allow-Headers"]="Content-Type,b"
            return response
    
  • 相关阅读:
    【SCP-GO-100】梦 中 染
    【scp系列】SCP-4711 不便利便利店
    【scp系列】SCP-2298 塑料盒里的生活
    【scp系列】SCP-CN-1219 关云长大战外星人
    【scp系列】SCP-4444 以米斯达之名
    使用Ubuntu搭建Owncloud私有云
    python中函数的使用初步
    IOS自动化环境搭建踩坑指南
    接口测试工具apifox
    windowns上搭建vscode+node.js开发环境
  • 原文地址:https://www.cnblogs.com/Pilaoban/p/13067543.html
Copyright © 2011-2022 走看看