同源策略(Same Origin Policy)是浏览器安全策略的重要组成部分,它限制了来自不同源的网页之间的数据交互,以防止恶意攻击。当一个网页尝试执行与它的源(即协议、域名和端口)不一致的请求时,浏览器会出于安全考虑拦截这个请求。
跨域资源共享(CORS, Cross-Origin Resource Sharing)是一个W3C规范,它允许某些跨源请求,如Ajax,从而克服了Ajax只能同源使用的限制。CORS需要浏览器和服务器同时支持,基本思想是使用自定义的HTTP头来让浏览器和服务器进行通信。
在Django项目中解决跨域问题,可以通过多种方法,包括手动编写中间件以及使用第三方库。你给出的示例展示了如何手动编写一个CORS中间件,以及如何使用django-cors-headers
这个流行的第三方库来简化CORS的设置。
手动编写CORS中间件:
中间件代码示例中,通过向响应头中添加适当的CORS相关头部,允许来自任何源的请求("Access-Control-Allow-Origin": "*"
)。同时,对于OPTIONS请求(预检请求),该中间件还允许所有的方法和头部。
使用django-cors-headers
库:
pip install django-cors-headers
settings.py
中添加'corsheaders'
到INSTALLED_APPS
。settings.py
的MIDDLEWARE
中添加'corsheaders.middleware.CorsMiddleware'
,并确保它在其他中间件之前(特别是在CommonMiddleware
之前)。CORS_ORIGIN_ALLOW_ALL
为True
来允许所有源的请求,或者你可以指定一个允许源的列表。CORS_ALLOW_METHODS
和CORS_ALLOW_HEADERS
分别定义了允许的HTTP方法和头部。 请注意,出于安全考虑,通常不建议在生产环境中设置CORS_ORIGIN_ALLOW_ALL
为True
,除非你完全理解可能的安全风险。在生产环境中,最好明确指定允许的源。
另外,值得注意的是,虽然CORS解决了浏览器端的跨域问题,但服务器端仍然需要验证请求的有效性,以防止潜在的安全威胁,如CSRF攻击。因此,即使启用了CORS,也不应忽视服务器端的安全性措施。
# 同源策略(Same origin policy)是一种约定,它规定了 请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同,如果不一致,请求会发送成功,后端会正常响应,但是浏览器会拦截 # 浏览器对非同源请求返回的结果做了拦截 # 只要做前后端分离,就会出跨域 # 解决跨域问题 -CORS :跨域资源共享 咱们讲的方式 向响应头中加数据,允许跨域 - 后端代码处理 - nginx代理 -JSONP :利用有的标签没有跨域问题 script img -websocket:长链接,不存在跨域 -前端代理:开发阶段用,上线不用 # cors如何解决跨域 -需要服务端支持---》就是服务端再响应头中加数据即可 # CORS基本流程 CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request) 简单请求,只发送一次: 非简单请求发送两次,第一次是OPTIONS预检请求,第二次是真正的请求 # 什么是简单,什么是非简单 #请求方法是以下三种方法之一: HEAD GET POST # HTTP的头信息不超出以下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain # 请求头中带了 token ,所有请求都是非简单 ### 解决跨域---统一写个中间件--》处理所有跨域 from django.utils.deprecation import MiddlewareMixin class CorsMiddleWare(MiddlewareMixin): def process_response(self,request,response): if request.method=="OPTIONS": #可以加* response["Access-Control-Allow-Headers"]="*" res['Access-Control-Allow-Methods'] = '*' response["Access-Control-Allow-Origin"] = "*" return response # 第三方解决方案 # 1、使用pip安装 pip install django-cors-headers #2、添加到setting的app中 INSTALLED_APPS = ( ... 'corsheaders', ... ) #3、添加中间件 MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', ... ] 4、setting下面添加下面的配置 CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', 'token' )
Access-Control-Allow-Headers
、Access-Control-Allow-Methods
和 Access-Control-Allow-Origin
是三个与跨源资源共享(CORS)相关的 HTTP 响应头。它们各自有不同的作用和使用方法。
作用:
使用方法:
https://example.com
,可以返回以下响应头:Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Origin: *
作用:
使用方法:
Access-Control-Allow-Methods: GET, POST
作用:
使用方法:
Access-Control-Request-Headers
字段,则 Access-Control-Allow-Headers
字段是必需的。它的值是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在“预检”中请求的字段。Content-Type
和 Authorization
,可以返回以下响应头:Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Origin
用于指定哪些源可以访问资源。Access-Control-Allow-Methods
用于指定哪些 HTTP 方法允许跨源请求。Access-Control-Allow-Headers
用于告知浏览器在跨域请求中,所允许的请求头字段。 这三个响应头通常一起使用,以确保跨源请求的安全性和可访问性。同时,它们也遵循 CORS 规范,确保浏览器和服务器之间的正确交互。
Access-Control-Allow-Origin
from rest_framework.views import APIView from lufy.utils.utils_response import APIResponse class CoreView(APIView): def get(self, request, *args, **kwargs): # return APIResponse(name="shazi",password='123123132',token='asdas.da.dasd') # return APIResponse(results=[{"user":'132'},{"hobby":['music','running']}]) return APIResponse(headers={"hobby":['music','running']})
首页
{{ dataFromServer.message }}
from rest_framework.views import APIView from lufy.utils.utils_response import APIResponse class CoreView(APIView): def get(self, request, *args, **kwargs): # # return APIResponse(headers={"hobby":['music','running']}) # No 'Access-Control-Allow-Origin' header is present on the requested resource. return APIResponse(headers={"Access-Control-Allow-Origin": '*'})
用于告知浏览器在跨域请求中,所允许的请求头字段
from django.urls import path from . import views from .views import LoggerView, ExceptionView,ResponseView,CoreView,core_view urlpatterns = [ # 日志 path('logg/', LoggerView.as_view(), name='home'), # 异常 path('except/', ExceptionView.as_view()), # 响应方法 path('ponse/', ResponseView.as_view()), # 跨域 path('core/', CoreView.as_view()), path('option/', core_view), ]
from rest_framework.views import APIView from lufy.utils.utils_response import APIResponse def core_view(request): res = HttpResponse("ok") res['Access-Control-Allow-Origin'] = '*' if request.method =='OPTIONS': res['Access-Control-Allow-Headers'] = '*' return res
Access-Control-Allow-Methods
res['Access-Control-Allow-Headers'] = '*'
def core_view(request): res = HttpResponse("ok") res['Access-Control-Allow-Origin'] = '*' if request.method =='OPTIONS': res['Access-Control-Allow-Headers'] = '*' res['Access-Control-Allow-Methods'] = '*' return res
# 注意注释跨域403 MIDDLEWARE = [ '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', ]
非简单请求(non-simple requests)在CORS(跨源资源共享)中,指的是不满足简单请求条件的请求。简单请求和非简单请求的区分主要是基于HTTP请求的一些特性,而不仅仅是基于发送了几次请求。
简单请求需要满足以下条件:
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
如果HTTP请求不满足以上条件,那么它就是一个非简单请求。
非简单请求在浏览器发送真正的请求之前,会首先发送一个预检请求(preflight request),请求方法是OPTIONS。预检请求会询问服务器是否允许该跨域请求。服务器响应预检请求时,需要包含一些CORS相关的响应头信息,比如 Access-Control-Allow-Origin
、Access-Control-Allow-Methods
、Access-Control-Allow-Headers
等,来告知浏览器该跨域请求是否被允许。
所以,非简单请求并不是看你发送了几次请求,而是看请求的HTTP方法、头信息等是否满足简单请求的条件。如果不满足,浏览器就会发送预检请求,这增加了一次额外的HTTP请求。
from rest_framework.views import APIView from lufy.utils.utils_response import APIResponse def core_view(request): res = HttpResponse("ok") return res
from django.urls import path from . import views from .views import core_view urlpatterns = [ # option path('option/', core_view), ]
## 中间件### from django.utils.deprecation import MiddlewareMixin class CorsMiddleWare(MiddlewareMixin): def process_response(self,request,response): if request.method=="OPTIONS": #可以加* response["Access-Control-Allow-Headers"]="*" response['Access-Control-Allow-Methods'] = '*' response["Access-Control-Allow-Origin"] = "*" return response
MIDDLEWARE = [ 'utils.utils_middleware.CorsMiddleWare', ]
首页
{{ res.message }}
# 1、使用pip安装 pip install django-cors-headers # 2、添加到setting的app中 INSTALLED_APPS = ( ... 'corsheaders', ... ) # 3、添加中间件 MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', ... ] # 4、setting下面添加下面的配置 CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', 'token', ) ### 中间件源码分析 if conf.CORS_ALLOW_ALL_ORIGINS and not conf.CORS_ALLOW_CREDENTIALS: response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*" if request.method == "OPTIONS": response[ACCESS_CONTROL_ALLOW_HEADERS] = ", ".join(conf.CORS_ALLOW_HEADERS) response[ACCESS_CONTROL_ALLOW_METHODS] = ", ".join(conf.CORS_ALLOW_METHODS)
# pip install django-cors-headers
INSTALLED_APPS = ( ... 'corsheaders', ... )
MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', ... ]
CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', 'token', )