zoukankan      html  css  js  c++  java
  • Django 之跨域问题

    一、为什么会有跨域问题?

    是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不是所有的请求都给做跨域,像是一般的href属性,a标签什么的都不拦截。

    二、解决跨域问题的两种方式

    三、JSONP

    先简单来说一下JSONP,具体详细详见上面JSONP

    JSONP是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。(创建一个回调函数,然后在远程服务上调用这个函数并且将json数据形式作为参数传递,完成回调)。

    四、CORS跨域

    随着技术的发展,现在的浏览器可以主动支持设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

    1、简单请求和复杂请求

    复制代码
    条件:
        1、请求方式:HEAD、GET、POST
        2、请求头信息:
            Accept
            Accept-Language
            Content-Language
            Last-Event-ID
            Content-Type 对应的值是以下三个中的任意一个
                                    application/x-www-form-urlencoded
                                    multipart/form-data
                                    text/plain
     
    注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
    复制代码

    2、简单请求和复杂请求的区别?

    简单请求:一次请求

    非简单请求:两次请求,在发送数据之前会先发第一次请求做‘预检’,只有‘预检’通过后才再发送一次请求用于数据传输。

    3、关于预检

    复制代码
    - 请求方式:OPTIONS
    - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
    - 如何“预检”
         => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
            Access-Control-Request-Method
         => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
            Access-Control-Request-Headers
    复制代码

    4、CORS的优缺点

    • CORS的优点:可以发任意请求
    • CORS的缺点:上是复杂请求的时候得先做个预检,再发真实的请求。发了两次请求会有性能上的损耗

    五、JSONP和CORS的区别

    JSONP:服务端不用修改,需要改前端。发jsonp请求

    JSONP:只能发GET请求

    CORS:前端的代码不用修改,服务端的代码需要修改。如果是简单请求的话在服务端加上一个响应头。

    CORS:可以发任意请求

    六、基于CORS实现ajax请求

    1、支持跨域,简单请求

    客户端

    复制代码
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width">
     7     <title>Title</title>
     8 </head>
     9 <body>
    10 <div>
    11     <h1>欢迎来到我的主页</h1>
    12     <button onclick="getData()">获取用户数据</button>
    13 </div>
    14 <script src="/static/jquery-1.12.4.min.js"></script>
    15 <script>
    16     function getData() {
    17         $.ajax({
    18             url:'http://127.0.0.1:8080/index/',
    19             type:"GET",
    20             success:function (data) {
    21                 console.log(data)
    22             }
    23 
    24         })
    25     }
    26 </script>
    27 </body>
    28 </html>
    复制代码

    服务端

    复制代码
     1 from django.shortcuts import render
     2 from django.http import JsonResponse
     3 from rest_framework.views import APIView
     4 
     5 # Create your views here.
     6 class IndexView(APIView):
     7     def get(self,request,*args,**kwargs):
     8         ret = {
     9             'code': 111,
    10             'data': '你好吗?'
    11         }
    12         response = JsonResponse(ret)
    13         response['Access-Control-Allow-Origin'] = "*"
    14         return response
    复制代码

    2、支持跨域,复杂请求

    如果是复杂请求在你真正的发请求之前,会先偷偷的发一个OPTION请求,先预检一下,我

    允许你来你才来

    如果想预检通过就得写个option请求

    复制代码
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width">
     7     <title>Title</title>
     8 </head>
     9 <body>
    10 <input type="button" value="获取用户数据" onclick="getUser()">
    11 <script src="/static/jquery-1.12.4.min.js"></script>
    12 <script>
    13     function getUser() {
    14         $.ajax({
    15             url:'http://127.0.0.1:8080/user/',
    16             type:'POST',
    17             data:{'k1':'v1'},
    18             headers:{
    19                 'h1':'sdfdgfdg'
    20             },
    21             success:function (ret) {
    22                 console.log(ret)
    23             }
    24         })
    25     }
    26 </script>
    27 </body>
    28 </html>
    复制代码
    复制代码
     1 from django.shortcuts import render,HttpResponse
     2 from django.http import JsonResponse
     3 from rest_framework.views import APIView
     4 
     5 class UserIndex(APIView):
     6     def get(self,request,*args,**kwargs):
     7         ret = {
     8             'code': 111,
     9             'data': '你好吗?'
    10         }
    11         response = JsonResponse(ret)
    12         response['Access-Control-Allow-Origin'] = "*"
    13         return response
    14 
    15     def post(self,request,*args,**kwargs):
    16         print(request.POST.get('k1'))
    17         ret = {
    18             'code':1000,
    19             'data':'过年啦',
    20         }
    21         response = JsonResponse(ret)
    22         response['Access-Control-Allow-Origin'] = "*"
    23         return response
    24 
    25     def options(self, request, *args, **kwargs):
    26         # self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
    27         # self.set_header('Access-Control-Allow-Headers', "k1,k2")
    28         # self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
    29         # self.set_header('Access-Control-Max-Age', 10)
    30 
    31         response = HttpResponse()
    32         response['Access-Control-Allow-Origin'] = '*'
    33         response['Access-Control-Allow-Headers'] = 'h1'
    34         # response['Access-Control-Allow-Methods'] = 'PUT'
    35         return response
    复制代码

    由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。

    • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
    • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
    • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age

    3、跨域获取响应头

    默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。

    复制代码
     1 <!DOCTYPE html>
     2 <html>
     3 <head lang="en">
     4     <meta charset="UTF-8">
     5     <title></title>
     6 </head>
     7 <body>
     8 
     9     <p>
    10         <input type="submit" onclick="XmlSendRequest();" />
    11     </p>
    12 
    13     <p>
    14         <input type="submit" onclick="JqSendRequest();" />
    15     </p>
    16 
    17     <script type="text/javascript" src="jquery-1.12.4.js"></script>
    18     <script>
    19         function XmlSendRequest(){
    20             var xhr = new XMLHttpRequest();
    21             xhr.onreadystatechange = function(){
    22                 if(xhr.readyState == 4) {
    23                     var result = xhr.responseText;
    24                     console.log(result);
    25                     // 获取响应头
    26                     console.log(xhr.getAllResponseHeaders());
    27                 }
    28             };
    29             xhr.open('PUT', "http://c2.com:8000/test/", true);
    30             xhr.setRequestHeader('k1', 'v1');
    31             xhr.send();
    32         }
    33 
    34         function JqSendRequest(){
    35             $.ajax({
    36                 url: "http://c2.com:8000/test/",
    37                 type: 'PUT',
    38                 dataType: 'text',
    39                 headers: {'k1': 'v1'},
    40                 success: function(data, statusText, xmlHttpRequest){
    41                     console.log(data);
    42                     // 获取响应头
    43                     console.log(xmlHttpRequest.getAllResponseHeaders());
    44                 }
    45             })
    46         }
    47 
    48 
    49     </script>
    50 </body>
    51 </html>
    52 
    53 HTML
    复制代码
    复制代码
     1 class MainHandler(tornado.web.RequestHandler):
     2     
     3     def put(self):
     4         self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
     5 
     6         self.set_header('xxoo', "seven")
     7         self.set_header('bili', "daobidao")
     8 
     9         self.set_header('Access-Control-Expose-Headers', "xxoo,bili")
    10 
    11 
    12         self.write('{"status": true, "data": "seven"}')
    13 
    14     def options(self, *args, **kwargs):
    15         self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
    16         self.set_header('Access-Control-Allow-Headers', "k1,k2")
    17         self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
    18         self.set_header('Access-Control-Max-Age', 10)
    19 
    20 Tornado
    复制代码

    4、跨域传输cookie

    在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。

    如果想要发送:

    • 浏览器端:XMLHttpRequest的withCredentials为true
    • 服务器端:Access-Control-Allow-Credentials为true
    • 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
    复制代码
     1 <!DOCTYPE html>
     2 <html>
     3 <head lang="en">
     4     <meta charset="UTF-8">
     5     <title></title>
     6 </head>
     7 <body>
     8 
     9     <p>
    10         <input type="submit" onclick="XmlSendRequest();" />
    11     </p>
    12 
    13     <p>
    14         <input type="submit" onclick="JqSendRequest();" />
    15     </p>
    16 
    17     <script type="text/javascript" src="jquery-1.12.4.js"></script>
    18     <script>
    19         function XmlSendRequest(){
    20             var xhr = new XMLHttpRequest();
    21             xhr.onreadystatechange = function(){
    22                 if(xhr.readyState == 4) {
    23                     var result = xhr.responseText;
    24                     console.log(result);
    25                 }
    26             };
    27 
    28             xhr.withCredentials = true;
    29 
    30             xhr.open('PUT', "http://c2.com:8000/test/", true);
    31             xhr.setRequestHeader('k1', 'v1');
    32             xhr.send();
    33         }
    34 
    35         function JqSendRequest(){
    36             $.ajax({
    37                 url: "http://c2.com:8000/test/",
    38                 type: 'PUT',
    39                 dataType: 'text',
    40                 headers: {'k1': 'v1'},
    41                 xhrFields:{withCredentials: true},
    42                 success: function(data, statusText, xmlHttpRequest){
    43                     console.log(data);
    44                 }
    45             })
    46         }
    47 
    48 
    49     </script>
    50 </body>
    51 </html>
    52 
    53 HTML
    复制代码
    复制代码
     1 class MainHandler(tornado.web.RequestHandler):
     2     
     3     def put(self):
     4         self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
     5         self.set_header('Access-Control-Allow-Credentials', "true")
     6         
     7         self.set_header('xxoo', "seven")
     8         self.set_header('bili', "daobidao")
     9         self.set_header('Access-Control-Expose-Headers', "xxoo,bili")
    10 
    11         self.set_cookie('kkkkk', 'vvvvv');
    12 
    13         self.write('{"status": true, "data": "seven"}')
    14 
    15     def options(self, *args, **kwargs):
    16         self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
    17         self.set_header('Access-Control-Allow-Headers', "k1,k2")
    18         self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
    19         self.set_header('Access-Control-Max-Age', 10)
    复制代码

    来自于:http://www.cnblogs.com/haiyan123/p/8436452.html

  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/maojiang/p/9432061.html
Copyright © 2011-2022 走看看