Django之跨域请求
同源策略
首先基于安全的原因,浏览器是存在同源策略这个机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。
而如果我们要跳过这个策略,也就是说非要跨域请求,那么就需要通过JSONP或者CORS来实现了。
JSONP
什么是JSONP
首先提一下JSON这个概念,JSON是一种轻量级的数据传输格式,被广泛应用于当前Web应用中。JSON格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以JSON格式进行数据的传输。
那么JSONP是什么呢?
首先抛出浏览器同源策略这个概念,为了保证用户访问的安全,现代浏览器使用了同源策略,即不允许访问非同源的页面,详细的概念大家可以自行百度。这里大家只要知道,在ajax中,不允许请求非同源的URL就可以了,比如www.a.com下的一个页面,其中的ajax请求是不允许访问www.b.com/c.php这样一个页面的。
JSONP就是用来解决跨域请求问题的,那么具体是怎么实现的呢?
JSONP原理
ajax请求受同源策略影响,不允许进行跨域请求,而script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
JSONP具体实现
127.0.0.1:8000中的index.html
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> $(".jsonp_test").click(function () { $.ajax({ url:"http://127.0.0.1:8008/service/", type:"get", dataType:"jsonp", // 伪造ajax 基于script jsonp: 'callbacks', //jsonpCallback:"alex", success:function (data) { console.log(data) } }) }) <button class='jsop_test'>测试</button> </body> </html>
127.0.0.1:8080的views
import json def jsonp_test(request): func=request.GET.get("callbacks") #获取请求的callbacks参数 info={"name":"fuyong","age":18} #定义数据 return HttpResponse(" ('%s')"%(func,json.dumps(info))) #传json对象
总结
一句话就是利用script标签绕过同源策略,获得一个类似这样的数据。ajax里边的callbacks本质上是(伪装成script标签src属性发送请求的方式)发送一个回调方法,参数data就是想得到的json数据。
cors
CORS 定义
Cross-Origin Resource Sharing(CORS)跨来源资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。
CORS 对比 JSONP
都能解决 Ajax直接请求普通文件存在跨域无权限访问的问题
- JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求
- 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理
- JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS
CORS 实现思路
CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。
例如 localhost:63343 通过Ajax请求http://192.168.10.61:8080服务器资源时就会出现如下异常:
其实数据已经获取到了,但是由于同源策略的限制给禁止了,提示说header里没有Access-Control-Allow-Origin,那么,我们在发送响应的时候的只需要给header里加上这个参数就行了。
CORS的实现
CORS有很多种实现方式,这里介绍一种最简单最直观的的方式,就是修改views.py中对应函数,给它的响应头部添加Access-Control-Allow-Origin餐具允许其他域通过Ajax请求数据,如下:
def cors_test(request): info={"name":"egon","age":34,"price":200} #数据 response=HttpResponse(json.dumps(info)) #序列化数据 #response["Access-Control-Allow-Origin"]="http://127.0.0.1:8006" #指定ip可访问 #response["Access-Control-Allow-Origin"]="*"#所有ip均可访问 return response #返回数据
实例
下面的代码实现了通过添加中间件的方式实现跨域请求
cors.py
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response class CORSMiddleware(MiddlewareMixin): def process_response(self,request,response): # 添加响应头 # 允许你的域名来获取我的数据 response['Access-Control-Allow-Origin'] = "*" # 允许你携带Content-Type请求头 response['Access-Control-Allow-Headers'] = "Content-Type" # 允许你发送DELETE,PUT response['Access-Control-Allow-Methods'] = "DELETE,PUT" return response
settings.py
MIDDLEWARE = [ ..... 'xxx.cors.CORSMiddleware', # xxx为cors.py所在包的目录 ]