同源策略與Jsonp
同源策略
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。javascript
示例:非同源請求報錯(項目端口不一樣)
STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), )
靜態文件: html
<script src="http://code.jquery.com/jquery-latest.js"></script>前端
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'index/$',views.index),
url(r'ajax_send/$',views.ajax_send),
]
from django.shortcuts import render,HttpResponse def index(request): return render(request,"index.html") def ajax_send(request):
print('項目1...............') return HttpResponse("項目1的數據")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h3>pro1的首頁</h3>
<button class="b1">send a request</button>
</body>
<script src="/static/jquery.js"></script>
<script>
$(".b1").click(function(){
$.ajax({
//url:"/ajax_send/", //訪問項目1的本路徑
url:"http://127.0.0.1:8080/ajax_send/", //訪問項目2的路徑,同源策略接收不到數據。
success:function(data){
alert(data);
}
})
})
</script>
</html>
項目2的代碼同上java
//===================================setting.py STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), ) //===================================urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'index/$',views.index), url(r'ajax_send/$',views.ajax_send), ] //===================================views.py from django.shortcuts import render,HttpResponse def index(request): return render(request,"index.html") def ajax_send(request):
print('項目2..............') return HttpResponse("項目2的數據") //===================================index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h3>pro2的首頁</h3> <button class="b2">send a request</button> </body> <script src="/static/jquery.js"></script> <script> $(".b2").click(function(){ $.ajax({ url:"/ajax_send/", success:function(data){ alert(data); } }) }) </script> </html>
同源問題: 當點擊項目1的按鈕時,發送了請求,可是會發現報錯以下:python
已攔截跨源請求:同源策略禁止讀取位於 http://127.0.0.1:7766/SendAjax/ 的遠程資源。(緣由:CORS 頭缺乏 'Access-Control-Allow-Origin')。
可是注意,項目2中的訪問已經發生了,說明是瀏覽器對非同源請求返回的結果作了攔截。jquery
注意:jquery.js也是非同源請求,但卻能拿到數據。script標籤請求不攔截,就攔截ajax請求。
script標籤請求:
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h3>pro1的首頁</h3> <button class="b1">send a request</button> </body> <script src="/static/jquery.js"></script> <script> /* $(".b1").click(function(){ $.ajax({ //url:"/ajax_send/", //訪問項目1的本路徑 url:"http://127.0.0.1:8080/ajax_send/", //訪問項目2的路徑 success:function(data){ alert(data); } }) }) */ </script> <!-- 單發一個script請求。刷新頁面則請求。--> <script src="http://127.0.0.1:8080/ajax_send/"></script> </html>
刷新頁面:ajax
項目2的返回值改爲英文。定義成一個變量。django
from django.shortcuts import render,HttpResponse def index(request): return render(request,"index.html") def ajax_send(request): print('項目2.........') # return HttpResponse("項目2的數據") return HttpResponse("baobao")
項目1的js中定義baobao這個變量。運行結果:頁面不會報錯了。json
<script>
var baobao="貝貝";
</script>
<!-- 單發一個script請求。刷新頁面則請求。-->
<script src="http://127.0.0.1:8080/ajax_send/"></script>
運行結果:頁面不會報錯了。跨域
定義一個變量是沒有意義的。接下來項目1的js中定義一個函數。
項目1的js中定義一個函數:
<script> // 定義函數 function baobao(){ console.log('貝貝'); } // baobao(); //調用函數 </script> <!-- 單發一個script請求。刷新頁面則請求。--> <script src="http://127.0.0.1:8080/ajax_send/"></script>
項目2返回的值是一個調用函數的字符串。至關於調用了項目1裏的函數。
def ajax_send(request): print('項目2.........') # return HttpResponse("項目2的數據") # return HttpResponse("baobao") return HttpResponse("baobao()")
刷新項目1的頁面,運行結果以下:
本質項目1想拿項目2的數據。
項目2實參上傳些值給項目1.
def ajax_send(request): print('項目2.........') # return HttpResponse("項目2的數據") # return HttpResponse("baobao") # return HttpResponse("baobao()") return HttpResponse("baobao('項目2的數據')")
項目1接收傳參:
<script> function baobao(s){ console.log(s); } // baobao('項目2的數據'); //調用函數 </script> <!-- 單發一個script請求。刷新頁面則請求。--> <script src="http://127.0.0.1:8080/ajax_send/"></script>
運行結果:
假設項目2不發送字符串,而是發送字典類型的數據給項目1。項目1該如何接收???
項目2:序列化字典:json.dumps(res)
def ajax_send(request): print('項目2.........') # return HttpResponse("項目2的數據") # return HttpResponse("baobao") # return HttpResponse("baobao()") # return HttpResponse("baobao('項目2的數據')") res={"name":"寶寶"} import json return HttpResponse("baobao('%s')"%json.dumps(res))
項目1:反序列化數據:JSON.parse(s); JSONP的來歷!!!!
<script> // 接收傳參 // 定義函數 function baobao(s){ console.log(s); JSON.parse(s); } // baobao('項目2的數據'); //調用函數 </script> <!-- 單發一個script請求。刷新頁面則請求。--> <script src="http://127.0.0.1:8080/ajax_send/"></script>
項目1刷新頁面:運行結果:
接下來動態定義函數名!!!
項目1傳的的是什麼函數名,項目2就是動態的函數名。
項目1:
<script> // 定義函數 function foo(s){ console.log(s); JSON.parse(s); } </script> <!-- 項目1傳的的是什麼函數名,項目2就是動態的函數名。--> <script src="http://127.0.0.1:8080/ajax_send/?a=foo"></script>
項目2:
def ajax_send(request): print('項目2.........') func = request.GET.get("a") res={"name":"寶寶"} import json return HttpResponse("%s('%s')"%(func,json.dumps(res)))
運行結果:
思考:以上都是刷新頁面發送請求的,如何點擊按鈕發送請求呢???
項目1中新增一個按鈕,點擊b2發送請求。
項目1的index.html:
<button class="b2">send a request_b2</button>
<script> // 思考:以上都是刷新頁面發送請求的,如何點擊按鈕發送請求呢??? $(".b2").click(function(){ // 建立一個script標籤,添加到body中。 var $ele_script = $("<script>"); $ele_script.attr("src","http://127.0.0.1:8080/ajax_send/?a=foo"); $("body").append($ele_script); }) </script>
運行結果:
項目1:封裝功能代碼:把路徑當成參數動態傳值。而且清空該標籤。
項目1:index.html
// 定義函數 function foo(s){ console.log(s); JSON.parse(s); } // 封裝功能代碼:把路徑當成參數動態傳值。 function kuayu(url){ // 建立一個script標籤,添加到body中。 var $ele_script = $("<script>"); $ele_script.attr("src",url); $ele_script.attr("class","kuayu"); $("body").append($ele_script); //發送請求 // 請求完成以後刪除該標籤 $(".kuayu").remove() }; $(".b2").click(function(){ kuayu("http://127.0.0.1:8080/ajax_send/?a=foo") });
基於jqeury的API實現跨越請求
//====================基於jqeury的API實現跨越請求====================
對script請求的封裝
項目1:
//====================基於jqeury的API實現跨越請求====================
$(".b2").click(function(){
// 跨域請求
$.getJSON("http://127.0.0.1:8080/ajax_send/?a=?",function(data){
console.log(data);
});
});
a是一個隨機字符串的函數名。
項目2:
def ajax_send(request): print('項目2.........') func = request.GET.get("a") print("func",func) res={"name":"寶寶"} import json return HttpResponse("%s('%s')"%(func,json.dumps(res)))
項目2運行結果:
結果是同樣的,要注意的是在url的後面必須添加一個callback參數,這樣getJSON方法纔會知道是用JSONP方式去訪問服務,callback後面的那個問號是內部自動生成的一個回調函數名。
此外,若是說咱們想指定本身的回調函數名,或者說服務上規定了固定回調函數名該怎麼辦呢?咱們可使用$.ajax方法來實現
$.ajax
//====================基於jqeury的API(ajax)實現跨越請求====================
項目1:
//====================基於jqeury的API(ajax)實現跨越請求==================== function baobao(s){ console.log(s); } $(".b2").click(function(){ $.ajax({ url:'http://127.0.0.1:8080/ajax_send/', //url:'http://127.0.0.1:8080/ajax_send/?a=baobao', 至關於 dataType:'jsonp', // 期待數據類型.會生成script標籤請求。 jsonp: 'a', // 鍵 jsonpCallback:"baobao" // 值 }) });
項目1運行結果:
項目2運行結果:
//====================以上代碼仍是要自定義函數,接下來終極版!!!====================
項目1:
//====================以上代碼仍是要自定義函數,接下來終極版!!!==================== $(".b2").click(function(){ $.ajax({ url:'http://127.0.0.1:8080/ajax_send/', //url:'http://127.0.0.1:8080/ajax_send/?a=隨機字符串', dataType:'jsonp', // 期待數據類型.會生成script標籤請求。 jsonp: 'a', //鍵 success:function(data){ console.log(data); } }) });
項目2的運行結果:
應用:
// ========================================================================================= // 應用 $(".b2").click(function(){ $.ajax({ url:'http://www.jxntv.cn/data/jmd-jxtv2.html?', dataType:'jsonp', // 期待數據類型.會生成script標籤請求。 jsonp: 'callback', //鍵 jsonCallback:"list" }); }); function list(data){ //console.log(data.data); $.each(data.data,function(i,weekday){ //console.log(weekday); // {week: "週日", list: Array(19)} $("body").append("<p>"+ weekday.week +"</p>"); //console.log(weekday.list); // {19個數據} 0:{time: "0030", name: "通宵劇場六集連播", link: "http://www.jxntv.cn/live/jxtv2.shtml"} $.each(weekday.list,function(j,show){ s="<p><a href='+ show.link +'>"+ show.name +"</a><p>" $("body").append(s); }) }); };
運行結果:
總結:
jsonp是json用來跨域的一個東西。原理是經過script標籤的跨域特性來繞過同源策略。
JSONP的原型:建立一個回調函數,而後在遠程服務上調用這個函數而且將JSON 數據形式做爲參數傳遞,完成回調。
將JSON數據填充進回調函數,這就是JSONP的JSON+Padding的含義。
jQuery框架也固然支持JSONP,可使用$.getJSON(url,[data],[callback])方法
<script> function f(){ $.ajax({ url:"http://127.0.0.1:7766/SendAjax/", dataType:"jsonp", //必須有,告訴server,此次訪問要的是一個jsonp的結果。 jsonp: 'callbacks', //jQuery幫助隨機生成的:callbacks="wner" success:function(data){ alert("hi "+data) } }); } </script>
jsonp: 'callbacks'就是定義一個存放回調函數的鍵,jsonpCallback是前端定義好的回調函數方法名'SayHi',server端接受callback鍵對應值後就能夠在其中填充數據打包返回了;
jsonpCallback參數能夠不定義,jquery會自動定義一個隨機名發過去,那前端就得用回調函數來處理對應數據了。利用jQuery能夠很方便的實現JSONP來進行跨域訪問。
注意 JSONP必定是GET請求