ajax-解決跨域請求(基於js,jQuery的josnp,設置響應頭的cors)


同源策略

同源策略(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))
View Code

 

項目二的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>
View Code

 

 注意 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請求,拿到數據,最后給項目一。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM