Django解决跨域请求:CORS原理、JsonP与中间件配置详解
本文详细解析Django中处理跨域请求的两种主要方式。首先介绍CORS(跨域资源共享)机制,区分简单请求与复杂请求(预检OPTIONS),并通过Django中间件配置响应头实现全类型跨域。其次回顾JsonP技术,利用script标签绕过同源策略仅支持GET请求。文章提供完整代码示例,涵盖视图、HTML及中间件注册步骤,帮助开发者理解并实施跨域解决方案。
Django跨域处理概述
前言
CORS(Cross Origin Resource Sharing,跨域资源共享)是浏览器端解决跨域问题的核心机制。
在CORS规范下,跨域请求被划分为简单请求和复杂请求两类,两者的处理流程有所不同。
CORS机制与请求分类
简单请求
要被视为简单请求,必须同时满足以下两个条件。
HTTP请求方法仅限于HEAD、GET或POST这三种之一。
请求头(Headers)中不得包含除以下字段之外的任何自定义字段:
Accept、Accept-Language、Content-Language、Last-Event-ID
此外,Content-Type请求头的值必须严格限定为以下三种类型之一:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
任何不满足上述条件的请求,均被归类为复杂请求。
对于复杂请求,浏览器会先自动发送一个预检请求(Preflight),即OPTIONS请求,以确认服务器是否允许该跨域操作。
浏览器同源策略解析
浏览器的同源策略
跨域访问受限的根本原因在于浏览器遵循的同源策略。
这意味着,浏览器默认会拦截非同源的资源请求。
所谓非同源,是指域名、协议或端口中任意一项与当前页面不一致的情况。
需要注意的是,浏览器仅限制表单提交和Ajax(XMLHttpRequest/Fetch)等脚本发起的跨域请求,而不会阻止通过src属性加载资源。
因此,CDN资源、图片等通过src属性引用的跨域加载行为是正常的。
JsonP跨域方案
JsonP实现跨域
JsonP(JSON with Padding)利用浏览器不限制src属性跨域的特性来实现数据交互。
由于script标签的特性,JsonP只能用于实现GET请求的跨域。
首先准备后端视图文件。
from django.http import HttpResponse
from rest_framework.views import APIView
class TestView(APIView):
def get(self, request):
return HttpResponse("handlerResponse('is ok')")
# 注意返回的函数以及参数的格式
接着编写前端HTML文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>JsonP跨站请求测试</title>
</head>
<body>
<script>
// 函数名应为handlerResponse,这是一种约定俗成
function handlerResponse(data) {
alert(data)
}
</script>
<!--必须放在被执行函数的script标签的下面,否则会报错函数不存在-->
<script src="http://127.0.0.1:8000/test/"></script>
</body>
</html>
接下来进行实际测试。

从测试结果可以看出,我们成功实现了通过JsonP跨域获取数据。
然而,JsonP仅支持GET请求,且前后端交互逻辑较为繁琐,目前在实际项目中已较少使用。
Django中间件配置CORS
在Django中间件中添加响应头
通过配置Django中间件添加CORS响应头,可以同时支持简单请求和复杂请求的跨域访问。
第一步,准备中间件代码。
from django.utils.deprecation import MiddlewareMixin
class MyCors(MiddlewareMixin):
def process_response(self, request, response):
# 如下,等于'*'后,便可允许所有简单请求的跨域访问
response['Access-Control-Allow-Origin'] = '*'
# 判断是否为复杂请求
if request.method == 'OPTIONS':
response['Access-Control-Allow-Headers'] = 'Content-Type'
response['Access-Control-Allow-Methods'] = 'PUT,PATCH,DELETE'
return response
编写完成后,务必在Django配置文件中注册该中间件。
第二步,编写处理跨域请求的视图文件。
from django.http import HttpResponse
from rest_framework.views import APIView
class TestView(APIView):
def get(self, request):
return HttpResponse("这是GET请求的数据")
def post(self, request):
return HttpResponse("这是POST请求的数据")
def put(self, request):
return HttpResponse("这是PUT请求的数")
第三步,编写前端HTML测试文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<title>test</title>
</head>
<body>
<button id="sign">点击发送跨站请求</button>
<script>
$('#sign').click(function () {
$.ajax({
url: 'http://127.0.0.1:8000/test/', // 要访问的外站
type: 'put', // 请求类型, put为复杂请求
contentType: 'application/json', // 指定为'application/json'后,将变为复杂请求
success: function (data) {
// 请求成功后将执行该函数
// data是外站发送过来的数据
alert(data)
},
});
});
</script>
</body>
</html>
测试效果如下所示。

由此可见,我们成功实现了复杂请求的跨域,简单请求自然也能正常通过。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









