Django-解决跨域请求(基于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请求,拿到数据,最后给项目一。

 

posted @ 2018-01-07 18:20  liqianlong  阅读(5436)  评论(0编辑  收藏  举报