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
原文地址:https://www.cnblogs.com/Pilaoban/p/13067543.html