Python跨域处理详解:JSONP与CORS实战指南
本文详解Python后端处理浏览器跨域问题的两种主流方案。首先解析JSONP基于script标签的原理及GET请求限制,提供前后端完整代码示例;其次介绍通过响应头添加CORS参数及使用Django-cors-headers库的配置方法,支持所有HTTP请求类型,帮助开发者快速解决跨域报错。
跨域概念与同源策略基础
受限于浏览器的同源策略,不同源的脚本无法访问其他源下的资源。这种跨源访问即为广义上的跨域;而代码中向非同源域名发送HTTP请求则属于狭义跨域。
同源策略(SOP,Same Origin Policy)是浏览器最核心的安全机制。若缺失该策略,浏览器极易遭受XSS(跨站脚本攻击)和CSRF(跨站请求伪造)等安全威胁。
判断是否同源需检查协议、域名和端口号。若不确定,可在浏览器控制台输入window.location.origin查看返回值。
以下两种场景不受跨域限制,严格来说属于跨站资源请求:
1)页面中的链接跳转、重定向及表单提交不受同源策略限制。
2)跨域资源的引入,例如通过<script src="">、<image src="">或<iframe>等方式加载资源。
由上述第二种情况可知,通过src属性获取非同源资源时不受限制。基于此,我们可以思考是否利用这种跨站资源请求方式来实现HTTP跨域请求,即接下来要介绍的JSONP方案。
JSONP跨域方案原理与实现
1、JSONP(适用于所有GET请求,不仅限于Python)
1)实现原理:
既然Web页面请求跨站资源不受同源策略限制,我们可以尝试在服务器上生成包含所需数据的JS文件,并让Web端直接访问该JS文件以获取数据。鉴于JSON格式被JS原生支持,Web端即可通过访问动态生成的JS文件来获取跨域数据。
为便于客户端使用数据,逐渐形成了一种非正式传输协议:JSONP。其核心机制是向服务器传递一个callback参数,服务器返回数据时,将该callback参数作为函数名包裹JSON数据。
2)JSONP实例
在远程服务器新建remote.js文件:
HandleRemote({"title":"哈哈", "name":"我是一个测试数据哦!"})
在本地新建HTML文件:
function HandleRemote(data){
console.log(data.title+data.name);
}
<script type="text/javascript" src="远程服务器地址/remote.js">
运行本地文件后,在浏览器控制台可看到输出:哈哈我是一个测试数据哦!
至此实现了从服务器获取数据,还需解决两个问题:
a、如何告知远程服务器本地回调函数的名称?
b、如何在远程服务器上动态生成JS脚本?
思路明确后,先解决第一个问题:
如何让服务器知晓本地回调函数名?只需在请求中附带函数名,远程服务器根据该参数动态生成调用JS脚本即可!
前端实现
var url = "http://test.com/getRemoteDate?callback=HandleRemote"
var script = document.createElement("script");
script.setAttribute("src", url)
document.getElementByTagName("head")[0].appendChild(script);
最后将上述代码封装为通用的Ajax形式:
url = "http://test.com/getRemoteDate/";
$.ajax({
url:url,
type:"GET",
dataType:"JSONP",
jsonp:"callback", #将会作为参数传给服务器,用于获得回调函数的参数名
jsonCallback:"test", # 自定义的jsonp的回调函数参数名,默认为jQuery自动生成的函数名,也可以自定义,jQuery会自动为你处理的。
success:function(data){
此处data即为返回的json数据了,前端根据需要自行处理
}
});
服务端代码:
def getData():
return {"title":"哈哈", "name":"这又是一个测试数据哦!"}
def getRemote(request):
funcName = request.GET.get("callback")
result = getData()
# 将结果以json形式返回,与前端的jsonp交互
return funcName+"("+json.dumps(result)+")"
配置URL:
url(r"^getRemoteData/$", getRemote)
JSONP至此完成。虽然JSONP不受同源策略限制,但其仅支持GET请求,不支持其他类型请求。
CORS响应头与Django配置
2、在响应头中添加允许跨域的参数,告知浏览器服务器接受当前请求,此方式通用性强。
3、Python Django中最常用的另一种跨域处理方式:
使用Django提供的Django-cors-headers库处理跨域。
从GitHub下载Django-cors-headers。
pip install Django-cors-headers.zip
在settings.py的中间件中配置【'corsheaders.middleware.CorsMiddleware',】,务必将其置于CSRF中间件之前,通常建议放在最前面。
设置CORS_ORIGIN_ALLOW_ALL = True以允许所有跨域请求;也可设为False,并配合CORS_ORIGIN_WHITELIST白名单使用。
如此,跨域处理即告完成,且支持所有HTTP请求类型。
补充知识:Python WSGI解决跨域问题
import json
from wsgiref.simple_server import make_server
# application()函数是Python中符合WSGI标准的一个HTTP处理函数,返回是一个字符串
def application(environ, start_response):
# start_response 如下调用就会发送HTTP响应的Header,注意只能调用一次start_response()函数发送Header。
# start_response 函数两个参数,一是HTTP响应码,一是一组list表示的HTTP Header,每个Header用一个包含两个str的数组表示
status = '200 OK'
# response_headers 中添加请求头部 ,解决跨域问题
response_headers = [('Content-type', 'application/json'),
('Access-Control-Allow-Origin', '*'),
('Access-Control-Allow-Methods', 'POST'),
('Access-Control-Allow-Headers', 'x-requested-with,content-type'),
] # json
start_response(status, response_headers)
result = {'code': 200, 'message': "You get the flag"}
return [result.encode()]
if __name__ == "__main__":
port = 8091
httpd = make_server("127.0.0.1", port, application)
print("serving http on port {0}...".format(str(port)))
httpd.serve_forever()
以上关于Python跨域处理方式的详解内容,希望能为大家提供参考,感谢支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









