由于浏览器存在同源策略,同源策略指:浏览器 对不同源的脚本或文本的访问方式 进行的限制。比如源a的js不能读取或设置引入的源b的元素属性。
(阻止从一个源 加载文档 或脚本获取 或设置 另一个源 加载的文档的属性)。
定义同源:就是指两个页面具有相同的协议,主机(也常说域名),端口,三个要素缺一不可。
由于同源策略是浏览器的限制,所以请求的发送和响应是 可以进行,只不过浏览器不接受而已。
浏览器的同源策略并不是对所有的请求都制约:
制约:XmlHttpRequest
允许:img,script 等具有 src属性的标签
跨域名访问,如: http://www.c1.com域名 向 http://www.c2.com域名发送请求。
1.JSONP实现跨域请求
JSONP(JSONP - JSONP with Padding 是JSON的一种 ‘使用模式’),利用script标签的src属性(浏览器允许script标签跨域)
远程:
views.py
def get_data(request): import time time.sleep(3) func_name = request.GET.get('callback') return HttpResponse('%s("机密数据123")'%func_name)
本地:
views.py
def index(request): return render(request,'index.html')
index.html
<body> <h1>江山如此多娇</h1> <div id="i1"></div> <input type="button" onclick="jsonp('http://127.0.0.1:8001/get_data.html?callback=funcvv')" value="发送JSONP请求"/> <input type="button" onclick="Jsonp2()" value="发送JSONP2请求"> <input type="button" onclick="Jsonp3()" value="发送JSONP3请求"> <script src="/static/jquery-3.2.1.js"></script> <script> /* 手动实现jsonp */ function funcvv(arg) { alert(arg); } function jsonp(url) { tag = document.createElement('script'); tag.src = url; document.head.appendChild(tag); } function Jsonp2() { $.ajax({ url:'http://127.0.0.1:8001/get_data.html', type:'GET', dataType:'JSONP', success:function (data) { console.log(data); } }) } function list(arg) { console.log(arg); } function Jsonp3(){ $.ajax({ url: "http://127.0.0.1:8001/get_data.html", type: 'GET', dataType: 'JSONP', jsonp: 'callback', jsonpCallback: 'list' }) } </script> </body>
笔记:
- JSONP: 本地:先定义函数 远程:func("数据") 方式一:手动 /* function funcvvvvvv(arg) { alert(arg); document.head.removeChild(tag); } function jsonp(url){ tag = document.createElement('script'); tag.src = url; document.head.appendChild(tag); }*/ 方式二:调用jQuery function Jsonp2(){ $.ajax({ url: "http://127.0.0.1:8000/get_data.html", type: 'GET', dataType: 'JSONP', success: function(data){ console.log(data); } }) } 本质:创建script标签 编写跨域请求: 本地: function list666(arg){ } $.ajax({ url: "http://www.jxntv.cn/data/jmd-jxtv2.html", type: 'GET', dataType: 'JSONP', jsonp: 'callback', jsonpCallback: 'list666' }) 远程: func_name = request.GET.get('callback') return HttpResponse('%s("机密数据")' %func_name)
2.CORS
现在浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,是的浏览器允许跨域请求。
解决方法:
-------远程 def cors_data(request): response = HttpResponse('机密数据333') # response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' #设置某个能访问的域名 response['Access-Control-Allow-Origin'] = '*' #所有 return response --------本地 views.py def index_cors(request): return render(request,'index_cors.html') .HTML <body> <h1>大浪淘沙</h1> <script src="/static/jquery-3.2.1.js"></script> <script> $.ajax({ url:'http://127.0.0.1:8001/cors_data.html', type:'GET', success:function (data) { console.log(data); } }) </script> </body>
从而引出:
*简单请求 OR 非简单请求 条件: 1、请求方式:HEAD、GET、POST 2、请求头信息: Accept Accept-Language Content-Language Last-Event-ID Content-Type 对应的值是以下三个中的任意一个 application/x-www-form-urlencoded multipart/form-data text/plain 注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求 *简单请求和非简单请求的区别? 简单请求:一次请求 非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。 * 关于“预检” - 请求方式:OPTIONS - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息 - 如何“预检” => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers
PUT方法请求(非简单):
----远程 def cors_data(request): if request.method == 'OPTIONS': #预检 response = HttpResponse() #可为空 response['Access-Control-Allow-Origin'] = '*' response['Access-Control-Allow-Methods'] = 'PUT' return response elif request.method == 'PUT': response = HttpResponse('机密数据333') # response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' #设置某个能访问的域名 response['Access-Control-Allow-Origin'] = '*' #所有 return response -------本地 def index_cors(request): return render(request,'index_cors.html') <body> <h1>大浪淘沙</h1> <script src="/static/jquery-3.2.1.js"></script> <script> $.ajax({ url:'http://127.0.0.1:8001/cors_data.html', type:'PUT', #------PUT------ success:function (data) { console.log(data); } }) </script>
GET + 自定义headers(非简单):
--------远程 def cors_data(request): if request.method == 'OPTIONS': #预检 response = HttpResponse() #可为空 response['Access-Control-Allow-Origin'] = '*' # response['Access-Control-Allow-Methods'] = 'PUT' response['Access-Control-Allow-Headers'] = 'xxx' # 自定义的 headers:{'xxx':333}, return response elif request.method == 'GET': response = HttpResponse('机密数据333') # response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' #设置某个能访问的域名 response['Access-Control-Allow-Origin'] = '*' #所有 return response -------本地 def index_cors(request): return render(request,'index_cors.html') .HTML <body> <h1>大浪淘沙</h1> <script src="/static/jquery-3.2.1.js"></script> <script> $.ajax({ url:'http://127.0.0.1:8001/cors_data.html', type:'GET', headers:{'xxx':333}, success:function (data) { console.log(data); } }) </script> </body>
#补充:
JSONP:具有兼容性
CORS(早期有些浏览器版本,不支持)
不到不得已,才让发 非简单请求(会增加服务器压力)
例如:
笔记:
本地:无作为 远程:设置响应头 response['Access-Control-Allow-Origin'] = "http://127.0.0.1:8888" response['Access-Control-Allow-Methods'] = "PUT" response['Access-Control-Allow-Headers'] = "xxx"