用django分别建立两个项目,jsonp01和jsonp02,然后再在这两个项目里分别建立一个app,比如名字叫jsonp1、jsonp2;jsonp01的端口号是8005,jsonp02的端口号是8006。
jsonp1的代码如下,
setting做常规配置;
urls.py,
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^testjsonp/‘, views.testjsonp), url(r‘^index/‘, views.index), ]
views.py,
def testjsonp(request): return HttpResponse(‘OK‘) def index(request): return render(request,‘index.html‘)
index.html,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" onclick="ajaxjsonp1();" value="jsonp1" /> <script src="/static/js/jquery-1.12.4.js"></script> <script> function ajaxjsonp1() { $.ajax({ url : ‘/testjsonp/‘, type : ‘POST‘, data: {‘k1‘:‘v1‘}, success : function (data) { alert(data); } }); } </script> </body> </html>
jsonp2的代码如下,
settings.py做常规配置;
urls.py,
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^testjsonp2/‘, views.testjsonp2), ]
views.py,
def testjsonp2(request): return HttpResponse(‘jsonp2ok‘)
如上面的代码,因为jsonp1请求的是自己的项目域名(url : ‘/testjsonp/‘),所以会如期收到返回的数据并alert(ok);
当把url : ‘/testjsonp/‘改成url : ‘http://10.103.9.83:8006/testjsonp2/‘,即用ajax实现跨域请求(好比在www.taobao.com上通过ajax访问www.jd.com的数据),则会报错如下图,
这是因为自身浏览器的同源策略限制,比如在www.taobao.com上通过ajax访问www.jd.com的数据,该请求能从自己的浏览器发送到jd.com服务端,服务端也能处理并返回数据,但是当自己的浏览器发现收到的数据是非本机域名发来的,就会阻拦该数据,过程如下图,
,通过ajax,如果在当前域名去访问其他域名时,浏览器会出现同源策略限制,从而阻止请求的返回,所以无法用ajax实现跨域请求。
img、script、iframe、link这些标签是不受同源策略限制的;src属性一般不鸟同源策略。利用这个特点,就可以实现jsonp的跨域请求。
改进jsonp1的index.html的代码,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" onclick="ajaxjsonp1();" value="jsonp1" /> <input type="button" onclick="ajaxjsonp2();" value="jsonp2" /> <script src="/static/js/jquery-1.12.4.js"></script> <script> function ajaxjsonp1() { $.ajax({ url : ‘http://10.103.9.83:8005 /testjsonp/‘, type : ‘POST‘, data: {‘k1‘:‘v1‘}, success : function (data) { alert(data); } }); } function ajaxjsonp2() { #创建一个script标签,src值设置为要请求的域名,将这个标签加到head标签下,请求完之后remove掉这个标签。 var tag = document.createElement("script"); tag.src = "http://10.103.9.83:8006/testjsonp2/"; document.head.appendChild(tag); document.head.removeChild(tag); } </script> </body> </html>
然后点击index.html的“jsonp2”按钮,就会收到如下报错:
,这说明本地浏览器已经收到服务端返回的数据(jsonp2ok)了,但是这个返回的数据是交给javascripts处理的,因为script里没有“jsonp2ok”这个方法,所以会报错“jsonp2ok没有定义”,所以需要在服务端和客户端再做一些修改,代码见下,
jsonp2的views.py,
import json def testjsonp2(request): ll = [‘jack‘,‘luce‘,‘goi‘] #直接返回一个jsonpfunc(ll),然后客户端的script标签里需要定义一个jsonpfunc方法,然后就能处理数据了。 temp = ‘jsonpfunc(%s)‘ % (json.dumps(ll)) return HttpResponse(temp)
jsonp1的index.html,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" onclick="ajaxjsonp1();" value="jsonp1" /> <input type="button" onclick="ajaxjsonp2();" value="jsonp2" /> <script src="/static/js/jquery-1.12.4.js"></script> <script> function ajaxjsonp1() { $.ajax({ url : ‘http://10.103.9.83:8005 /testjsonp/‘, type : ‘POST‘, data: {‘k1‘:‘v1‘}, success : function (data) { alert(data); } }); } function ajaxjsonp2() { var tag = document.createElement("script"); tag.src = "http://10.103.9.83:8006/testjsonp2/"; document.head.appendChild(tag); document.head.removeChild(tag); } #收到服务端返回的数据,然后执行下面的jsonpfunc方法。 function jsonpfunc(data) { console.log(data); } </script> </body> </html>
现在再点击jsonp1的index.html的"jsonp2"按钮,返回数据见下:
,客户端收到这些数据后,就可以处理了。
上面讲的是jsonp的原理,原理就是利用那些不受同源策略限制的标签来发送请求,下面要说的是利用jquery实现伪ajax的跨域请求。
function weiajax(){ $.ajax({ url : ‘http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403‘, type : ‘GET‘, dataType : ‘jsonp‘, jsonp : ‘callback‘, jsonpCallback : ‘list‘ }); } function list(arg){ console.log(arg); } #这样就能获取到江西卫视的节目单了。 #注意,上面的function list(arg){}和 jsonpCallback : ‘list‘,之所以叫list,是因为江西卫视的服务器返回的数据中包含的javascript方法名叫list,所以我们也必须起名叫list,但是江西卫视是不规范的,规范的服务端应该是不限制客户端起什么方法名的;比如我本地有一个list方法,向江西卫视请求数据也需要定义一个list方法,那我岂不是要为了请求数据而将已有的list方法改名?显然是不合理的。但是江西卫视这么办了,我们就必须起这个名字。后面会讲到规范的方法。
如果是请求本地域名,就直接用ajax即可;如果是请求跨域数据,则依然用ajax,但是需要dataType : ‘jsonp‘、jsonp : ‘callback‘、jsonpCallback : ‘funcdemo‘,然后再定义一个function funcdemo(arg){}方法。
如果服务端规范的话,则客户端处理返回数据的方法名是任意起的,比如客户端可以这样请求数据,
function weiajax(){ $.ajax({ url : ‘http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403‘, type : ‘GET‘, dataType : ‘jsonp‘, jsonp : ‘callbackaaaaa‘, jsonpCallback : ‘listqqqqq‘ }); } function listqqqqq(arg){ console.log(arg); } #如果服务端规范的话,则客户端任意起方法名都不会影响接收数据,原因下面会讲到。
jsonp2的views.py的代码修改如下,
import json def testjsonp2(request): func = request.GET.get(‘callbackaaaaa‘) ll = [‘jack‘,‘luce‘,‘goi‘] #之前方法名是固定的,现在把方法名设置为变量了,方法名就是取的客户端发来的值,所以客户端发什么值,服务端就将这个值作为方法名返回给客户端。 temp = ‘%s(%s)‘ % (func,json.dumps(ll)) return HttpResponse(temp)
虽然“jsonp : ‘callbackaaaaa‘,”可以随便定义,但是为了客户端和服务端的统一,我们约定设置为“jsonp : ‘callback‘”,不然比如客户端是callbackaaa,但是服务端是“request.GET.get(‘callbackbbb‘)”,那肯定不能返回数据给客户端;
只要服务端如jsonp2的views所示将返回的方法名设置为变量,则客户端进行ajax跨域请求时,就可以随便定义方法名,listqqqqq也行、ll44也行、funcdemo也行等等。
jsonp的原理是利用那几个不受同源策略限制的标签的src属性来发送请求,比如<script src="http://www.baidu.com">,单单是写一个域名,所以肯定是GET请求,即使在$.ajax里指定了type:‘POST‘也不会起作用,本质上还是GET请求。
原文:http://www.cnblogs.com/fuckily/p/6367995.html