JSONP Ajax跨域
一、同源策略
在我们开始阐述跨域请求之前我们需要弄清楚什么是同源策略?因为跨域请求就是为了解决同源策略的问题。好了我们开始正题吧!
首先我们需要知道同源这个概念:同源指的是一个请求路径中的请求协议、ip及端口和另一个请求路径中的请求协议、ip及端口保持一致。同源策略是指:它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。举个例子:我们在浏览器中打开一个网页,当我们点击页面某个连接执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和当前页面同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
已django框架为例创建一个实例
<input type="text" name="user"> <button id="btn">获取</button> <script> $("#btn").click(function(){ $.ajax({ url:"jsonp.html", success:function(arg){ alert(arg) } }) }) </script>
视图send_ajax
def send_ajax(request): return render(request,'jsonp.html')
此种为正常情况,同过页面的点击按钮发送ajax请求,请求的路径为当前项目下的某个视图函数,此种显然符合同源策略。但是当我们把上述的ajax请求路径更改为另一个项目某个视图函数的路径,如:url:"http://127.0.0.1:8002jsonp.html/",此两个项目的端口不同。此时再发送ajax请求时,浏览器端会报如下错误:
已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8002/send_ajax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
注意,上述这种错误是由于浏览器的同源策略给我们抛出的,实际上是请求到了对应的视图函数,只是浏览器不会把这种非同源请求返回的数据给我们。
二、跨域请求
1、JSONP实现原理
web请求跨站请求是不受同源策略限制的,所有我们可以通过服务器将数据通过JS的形式传给web端,web端通过直接访问JS文件从而获得所需的数据,恰巧我们知道有一种叫做json的数据格式,且js原生支持,所以web端就可以通过像访问js脚本一样的方式,来调用跨域服务器上动态生成的js文件
为了便于客户端使用数据,逐渐形成一种非正式传输协议:JSONP。JSONP的一个要点就是,传给服务器一个callback参数,然后服务器返回数据时,将这个callback参数作为函数名来包裹住json数据
原理图:
实例一
#view def jsonp(request): # 以天气的接口为例 response = requests.get("http://weatherapi.market.xiaomi.com/wtr-v2/weather?cityId=101121301") # print(response.content) response.encoding='utf-8' # print(response.text) return render(request,"jsonp.html",{'result':response.text})
JS文件 <script> /* js 原生 function getContent(){ var xhr = new XMLHttpRequest(); xhr.open('GET','http://www.jxntv.cn/data/jmd-jxtv2.html'); xhr.onreadystatechange = function () { console.log(xhr.responseText); }; xhr.send(); }*/ /* var tag = document.createElement('script'); tag.src = "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403"; document.head.appendChild(tag); document.head.removeChild(tag); */ $.ajax({ url:'http://www.jxntv.cn/data/jmd-jxtv2.html', type:'GET', dataType:'jsonp', //相当于script标签 jsonp:'callback', //相当于路径中回调函数路径参数键值对的键 jsonpCallback:'list', //相当于路径中回调函数路径参数键值对的值,回调函数名 }) function list(arg){ console.log(arg); } </script>
实例二
前端实现 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){ console.log(data) } }); 服务端代码 : def getData():
#定义返回的数据 return {"precipitationMin":0,"tempMax":6,"tempMin":2,"weatherEnd":"晴","weatherStart":"阴","windDirectionEnd":"北风","windDirectionStart":"南风","windMax":5,"windMin":2}
def getRemote(request): funcName = request.GET.get("callback") result = getData() # 将结果以json形式返回,与前端的jsonp交互 return funcName+"("+json.dumps(result)+")"