Django 解决 CORS 跨域问题
Django
解决 CORS
跨域问题
★ CORS
基本概念
CORS(Cross-Origin Resource Sharing 跨域资源共享)是一种用于在Web浏览器中处理跨域请求的机制。跨域请求指的是在浏览器中,从一个域名的网页去请求另一个域名的资源。在默认情况下,浏览器限制了跨域请求,以保护用户的安全和隐私。
★ CORS
作用
浏览器采用了同源保护策略,为了防御恶意攻击,会检查Request消息与Response消息的域名 Domain与端口 Port,如果不相同,则表示响应消息与请求消息不是同源,可能是伪造的响应消息,因此浏览器添加了CORS限制功能,默认不接受非同源的响应消息。
★ CORS
工作机制
CORS通过在服务器端设置响应头来允许跨域请求。当浏览器发起跨域请求时,服务器可以在响应头中添加一些特定的字段,告诉浏览器该请求是被允许的。这些字段包括Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等。
Access-Control-Allow-Origin: 指定了允许访问该资源的域名。可以设置为特定的域名,也可以设置为*表示允许任意域名访问。
Access-Control-Allow-Methods: 指定了允许的HTTP方法,如GET、POST等。
Access-Control-Allow-Headers: 指定了允许的请求头。
浏览器在收到服务器的响应后,会检查响应头中的CORS字段,如果与当前页面的域名匹配并且字段值符合要求,浏览器就会允许该跨域请求,并将响应返回给页面。
-
说明
需要注意的是,CORS只在浏览器中起作用,不会影响非浏览器环境下的请求。此外,CORS并不能完全解决跨域问题,仍然需要其他安全措施来保护Web应用程序的安全性。 在跨源资源共享(CORS)的配置中,通常主要关注的是协议(如 http 或 https )、域名(如 example.com )。端口在某些情况下也需要考虑,但并非总是必需的。一般来说,如果你的前端应用和后端服务在默认端口上运行(例如 http 的 80 端口和 https 的 443 端口),那么在配置 CORS 时,不指定端口通常也能正常工作。然而,如果您的服务运行在非默认端口上(比如后端运行在 http://example.com:8080 ),那么为了确保 CORS 配置的准确性,建议在配置中明确指定端口,即 http://example.com:8080 。
★ 解决CORS
跨域请求的思路
-
方式一:通过自定义中间件修改
Response
头部-
1-在
myproject/myapp/
目录下,新建middlewares.py
文件存放中间件class CorsMiddleware(object): """中间件:跨域访问""" def __init__(self, get_response): self.get_response = get_response def __call__(self, request): return self.get_response(request) # process_template_response(), process_response() 只能二选一、根据view的response类型,重载相应方法。 def process_template_response(self,request,response): # 如果view 使用了render渲染response,使用这个中间件 response["Access-Control-Allow-Origin"] = "*" return response def process_response(self,request,response): # 如果view使用HttpResponse, 将使用这个中间件 response["Access-Control-Allow-Origin"] = "*" return response
-
2-将新定义的中间件
CorsMiddleware
添加到settings.py
的MIDDLEWARE
的列表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', 'myapp.middlewares.CorsMiddleware', # 允许跨域访问中间件 ]
-
3-测试
-
操作说明
再次发起跨域的Ajax请求,可以成功接收到django的响应数据。使用浏览器DevTools检查Response响应头部参数,可以看到已经添加了Access-Control-Allow-Origin: *
-
示例
HTTP/1.1 200 OK Date: Sat, 21 Aug 2023 08:26:17 GMT Server: WSGIServer/0.2 CPython/3.11.4 Content-Type: text/html; charset=utf-8 Access-Control-Allow-Origin: * X-Frame-Options: DENY Content-Length: 5177 Vary: Cookie X-Content-Type-Options: nosniff Referrer-Policy: same-origin
-
-
总结
此方法虽然简单易行,Access-Control-Allow-Origin 设置为*, 允许任何跨域访问,显然不太安全,每次修改须更新代码,因此仅适用于开发测试环境。
-
-
方式二:通过
django-cors-headers
库来实现 (生产环境下推荐使用)-
1-安装
pip install django-cors-headers
-
2-修改
settings.py
配置文件-
添加到应用列表
INSTALLED_APPS = ( ##... 'corsheaders' )
-
添加中间件列表
corsheaders.middleware.CorsMiddleware
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', # 注意顺序很重要,CorsMiddleware 应该在 CommonMiddleware 之前 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', ......
-
添加允许访问的域名
-
允许所有域名访问
CORS_ORIGIN_ALLOW_ALL = True
-
允许指定的域访问
CORS_ORIGIN_ALLOW_ALL = False # 如果你的API需要携带认证信息,如cookies或HTTP认证,则设置为True CORS_ALLOW_CREDENTIALS = True # 允许域名加入白名单 CORS_ORIGIN_WHITELIST = ( 'http//:localhost:8000', ) # 如果你的API需要特定的HTTP方法(例如DELETE, PUT),确保它们也被添加到CORS配置中 CORS_ALLOW_METHODS = [ 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', ] # 允许携带的HTTP头 CORS_ALLOW_HEADERS = [ 'accept', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrf-token', 'content-type', 'x-requested-with', # ... 其他自定义头 ... ]
-
-
-
★ 注意
缓存问题:有时浏览器会缓存CORS预检请求的结果。如果你更改了CORS设置,可能需要清除浏览器缓存或使用无痕/隐私模式来测试更改是否生效。
中间件顺序:确保corsheaders.middleware.CorsMiddleware在django.middleware.common.CommonMiddleware之前。
其他中间件冲突:检查你的中间件栈中是否有其他中间件可能与CORS中间件冲突或改变响应头。
★ 总结
在测试环境中,可以允许所有domain来访问,以避免 CORS问题,前后端分离项目在生产环境下,通常应该部署在同域下,
如果确实需要跨域,则将前端域名添加到白名单 CORS_ORIGIN_WHITELIST配置项中,禁止其它域访问。