同源策略
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
同源策略,它是由Netscape提出的一個著名的安全策略。現在所有支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,域名,協議,端口相同。當一個瀏覽器的兩個tab頁中分別打開來 百度和谷歌的頁面當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬於哪個頁面的,即檢查是否同源,只有和百度同源的腳本才會被執行。
如果非同源,那么在請求數據時,瀏覽器會在控制台中報一個異常,提示拒絕訪問。
url http ip port paht ? 數據
if 協議 IP PORT相同,同源
一,問題描述
1 django 創建2個項目 2 項目一,開啟一個send_ajax請求 http://127.0.0.1:8000 3 訪問正常 4 5 項目二,沒有send_ajax請求 http://127.0.0.1:8010 6 那么這時候如果你通過ajax訪問的 url:http://127.0.0.1:8000/send_ajax 7 瀏覽器會報錯,內容是已攔截跨域請求,同源策略禁止讀取位於http://127.0.0.1:8000/send_ajax遠程資源,原因:cors頭缺少 ‘Access-Control-Allow-Origin’
1.1 思考
jsonp是json用來跨域的一個東西。原理是通過script標簽的跨域特性來繞過同源策略。
1 跨域請求: 2 ajax請求一定會被攔截 3 4 核心任務:跨域請求的是數據,數據,數據 5 6 通過引入jquery cdn 可以跨域 我們想 是不是script標簽不會被攔截呢? 7 <script src=" https://cdn.bootcss.com/jquery/3.2.1/jquery.js "></script>
1.2跨域請求的演變
1 項目一 views 2 import json 3 def send_ajax(request): 4 return HttpResponse("yuan") # 第一次返回字符串 5 return HttpResponse("yuan()") # 第二次返回函數字符串 6 return HttpResponse("yuan('yuan')") # 第三次返回函數參數字符串 7 s='hello world' 8 return HttpResponse("yuan('%s')"%s) # 第四次返回函數字符串數據 9 10 s={"name":"egon","age":122} 11 return HttpResponse("%s('%s')"%(func_name,json.dumps(s))) # 第五次返回函數json字符串 12 13 項目二 html 14 第一次字符串,你要是知道數據是什么還請求干什么?所以這里只是個引子,告訴你可以這樣做 15 <script>yuan</script> 16 <script src="http://127.0.0.1:8000/send_ajax"></script> 17 18 19 第二次函數字符串 20 <script>function yuan(){alert(123)}</script> 21 <script src="http://127.0.0.1:8000/send_ajax"></script> 22 23 24 第三次返回函數參數字符串 25 <script>function yuan(arg){alert(arg)}</script> 26 <script src="http://127.0.0.1:8000/send_ajax"></script> 27 28 29 第四次返回函數字符串數據(數據也是字符串) 30 <script>function yuan(arg){alert(arg)}</script> 31 <script src="http://127.0.0.1:8000/send_ajax"></script> 32 33 34 第五次返回函數json字符串 35 <script>function yuan(arg){alert(Json.parse(arg))}</script> 36 <script src="http://127.0.0.1:8000/send_ajax"></script>
1.3問題
1 我不能硬生生的將<script src="http://127.0.0.1:8000/send_ajax"></script>寫在html里面,我需要動態創建下面的函數
我們通過觸發點擊事件函數創建
1 <script> 2 function yuan(arg) { 3 console.log(arg); 4 console.log(JSON.parse(arg)); 5 } 6 </script> 7 8 <script> 9 $(".send_ajax").click(function () { 10 kuayu_request("http://127.0.0.1:8000/send_ajax/") 11 }); 12 function kuayu_request(url) { 13 var $script=$("<script>"); // 創建script標簽,是一個jquery對象: <script> 14 $script.attr("src",url); 15 $("body").append($script); 16 $("body script:last").remove(); 17 } 18 </script>
1.4 問題
1 1 問題函數名字是不是可以通過請求傳送到后端呢?應該是同步的,可否通過回調函數?
可以通過發送請求的時候帶着數據,數據包含你的函數名稱,這樣傳到后端,再讓后端返回你這個函數和數據,就可以執行了
1 項目二 html 2 <script> 3 $(".send_ajax").click(function () { 4 kuayu_request("http://127.0.0.1:8000/send_ajax/?callback=bar") 5 }); 6 function kuayu_request(url) { 7 var $script=$("<script>"); // 創建script標簽,是一個jquery對象: <script> 8 $script.attr("src",url); 9 $("body").append($script); 10 $("body script:last").remove(); 11 } 12 </script> 13 14 15 項目一 views 16 def send_ajax(request): 17 func_name = request.GET.get('callback') 18 s = 'hello' 19 return HttpResponse("%s('%s')"%(func_name,json.dump(s)))
之前都是引子,下面才是真正的用法。。
ajax的跨域請求寫法
1 <script> 2 3 $(".send_ajax").click(function () { 4 5 $.ajax({ 6 url:"http://127.0.0.1:8000/send_ajax/", 7 success:function (data) { 8 alert(data) 9 }, 10 // 跨域請求 <script> 告訴服務器我要什么類型的數據contenttype是告訴服務器我是什么類型數據 11 dataType:"jsonp", 12 jsonp: 'callbacks', //?callbacks=SayHi 相當於這個,問題就是在於前后端的函數名要相同 13 jsonpCallback:"SayHi" 14 }) 15 16 17 }); 18 19 function SayHi(arg) { 20 console.log("hello",arg) 21 } 22 </script> 23 24 {#// ==========================================基於jquery的JSONP的實現3 (推薦)#} 25 26 <script> 27 28 $(".send_ajax").click(function () { 29 30 $.ajax({ 31 url:"http://127.0.0.1:8000/send_ajax/", 32 dataType:"jsonp", // 跨域請求 <script> 33 // callbacks=? ?就是隨機字符串了,后端傳回來運行的就是success函數,也就是funciton 函數參數是數據 34 jsonp: 'callbacks', 35 success:function (data) { 36 console.log(data) 37 } 38 }) 39 40 }); 41 42 </script>
jsonp的所有實現和應用例子
項目一的views.py
1 import json 2 def send_ajax(request): 3 s={"name":"egon","age":122} 4 return HttpResponse("list('%s')"%json.dumps(s))
項目二的index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js "></script> 7 </head> 8 <body> 9 <h1>項目2的首頁</h1> 10 <button class="send_ajax">send_ajax</button> 11 12 13 {#// ==========================================基於JS的JSONP的實現#} 14 <script> 15 function bar(arg) { 16 console.log(arg); 17 console.log(JSON.parse(arg)); 18 } 19 </script> 20 21 <script> 22 23 $(".send_ajax").click(function () { 24 kuayu_request("http://127.0.0.1:8000/send_ajax/?callback=bar") // 回調函數 25 }); 26 // 創建script添加scr屬性,獲取數據 27 function kuayu_request(url) { 28 var $script=$("<script>"); // 創建script標簽,是一個jquery對象: <script> 29 $script.attr("src",url); 30 $("body").append($script); 31 $("body script:last").remove(); 32 } 33 34 </script> 35 36 37 <hr> 38 39 {#// ==========================================基於jquery的JSONP的實現1#} 40 41 42 <script> 43 44 $(".send_ajax").click(function () { 45 // getJSON幫助我們創建了script標簽和src屬性 ,還有個參數,data= 可以寫入一些給后端的字符串 46 // 匿名函數,函數會有getJSON創建隨機字符串也就是callbacks=?的問好的值,函數參數的data是數據 47 $.getJSON("http://127.0.0.1:8000/send_ajax/?callbacks=?",function (data) { 48 console.log(data) 49 }) 50 }) 51 52 </script> 53 54 55 {#// ==========================================基於jquery的JSONP的實現2#} 56 57 <script> 58 59 $(".send_ajax").click(function () { 60 61 $.ajax({ 62 url:"http://127.0.0.1:8000/send_ajax/", 63 success:function (data) { 64 alert(data) 65 }, 66 // 跨域請求 <script> 告訴服務器我要什么類型的數據contenttype是告訴服務器我是什么類型數據 67 dataType:"jsonp", 68 jsonp: 'callbacks', //?callbacks=SayHi 相當於這個,問題就是在於前后端的函數名要相同 69 jsonpCallback:"SayHi" 70 }) 71 72 73 }); 74 75 function SayHi(arg) { 76 console.log("hello",arg) 77 } 78 </script> 79 80 {#// ==========================================基於jquery的JSONP的實現3 (推薦)#} 81 82 <script> 83 84 $(".send_ajax").click(function () { 85 86 $.ajax({ 87 url:"http://127.0.0.1:8000/send_ajax/", 88 dataType:"jsonp", // 跨域請求 <script> 89 // callbacks=? ?就是隨機字符串了,后端傳回來運行的就是success函數,也就是funciton 函數參數是數據 90 jsonp: 'callbacks', 91 success:function (data) { 92 console.log(data) 93 } 94 }) 95 96 }); 97 98 99 </script> 100 101 {#// =========================================應用#} 102 103 104 <script> 105 106 $(".send_ajax").click(function () { 107 108 $.ajax({ 109 url:"http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403", 110 dataType:"jsonp", 111 jsonp:"callback", 112 jsonpCallback:"list" 113 }) 114 115 116 }); 117 118 function list(shuju) { 119 console.log(shuju.data); // {data: Array(7)} 120 var data=shuju.data; // [{},{},{},......] 121 122 $.each(data,function (i,weekend) { 123 //console.log(weekend); // {week: "周日", list: Array(19)} 124 console.log(weekend.list); // {week: "周日", list: Array(19)} 125 var week= weekend.week; 126 $("body").append("<div>"+week+"</div>"); 127 128 $.each(weekend.list,function (i,show) { 129 console.log(show); // {time: "1800", name: "《都市現場》90分鍾直播版塊", link: "http://www.jxntv.cn/live/jxtv2.shtml"} 130 131 var $a=$("<a>"); // <a></a> 132 $a.html(show.name); 133 $a.attr("href",show.link); 134 135 $("body").append('<p>'); 136 $("body").append($a); 137 $("body").append('</p>'); 138 139 }) 140 141 142 }) 143 144 } 145 </script> 146 </body> 147 </html>
注意 JSONP一定是GET請求
CORS跨域資源共享(CORS,Cross-Origin Resource Sharing)
其本質是設置響應頭,使得瀏覽器允許跨域請求。
項目一要訪問項目二的視圖,項目二的ajax請求代碼如下
1 <h1>項目2的首頁cors</h1> 2 3 <button class="send_ajax">send_ajax</button> 4 5 <script> 6 7 $(".send_ajax").click(function () { 8 9 $.ajax({ 10 // 這里我訪問s1的的send_ajax 11 url:"http://127.0.0.1:8000/send_ajax/", 12 type:'GET', // head get post put delete 13 success:function (data) { 14 console.log(data); 15 console.log('11') 16 } 17 }) 18 19 }) 20 </script>
項目二通過路由找到視圖返回數據的代碼如下
1 import json 2 def send_ajax(request): 3 # 授權的origin可以用*代替所有,methods可以多個,用逗號分開,簡單的放一起,復雜放一起 4 if request.method == "OPTIONS": # 預檢 5 response = HttpResponse() 6 7 response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8011" 8 response["Access-Control-Allow-Methods"] = "PUT" 9 10 return response 11 12 elif request.method == "PUT": # 復雜請求,需要通過預檢 put delete 13 s = {"name": "egon", "age": 122} 14 15 response = HttpResponse(json.dumps(s)) 16 response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8011" 17 18 return response 19 20 elif request.method == 'GET': # 簡單強求 head get post 21 s = {"name": "egon", "age": 122} 22 23 response = HttpResponse(json.dumps(s)) 24 response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8011" 25 26 return response
流程:
項目二向項目一發送請求,項目一根據請求匹配路由規則,找到視圖,視圖首先返回給瀏覽器,如果沒有cors就會被瀏覽器攔截,有了cors設置,瀏覽器就不會攔截cors設置的請求方式,最終
返回給項目一的數據,上述例子中,復雜請求(put,delete)先走預檢,添加put請求,和允許訪問的url,返回給瀏覽器,瀏覽器得到后在向服務器發送put請求,拿到數據,最后給項目一。
