Ajax跨域請(qǐng)求_cors

cors

內(nèi)容回顧:
restful 規(guī)范
10個(gè)

  1. 除了 jsonp(它只可以發(fā) get 請(qǐng)求), 還有cors(可以發(fā)任何請(qǐng)求)。
    解決跨域一般方法:加響應(yīng)頭

  2. VUE + rest framework 示例

    • 登錄
    • 課程列表
      • 課程詳細(xì)
  3. django 里面的content-type:

    • django 的組件,幫我們做跨表的操作。

今日內(nèi)容

1. 跨域

  • 瀏覽器的同源策略導(dǎo)致跨域。

瀏覽器的同源策略:瀏覽器會(huì)將請(qǐng)求攔截,對(duì) ajax 請(qǐng)求進(jìn)行阻攔。對(duì) href,src屬性都不阻攔。
ps:
小公司:靜態(tài)文件服務(wù)器:js,cs 之類的靜態(tài)都放在里面。
大公司:CDN

解決方案:
      - 客戶端瀏覽器
      - 請(qǐng)求的是 pythondv
      - 發(fā)送的請(qǐng)求是 $.ajax(pythonav)
  -------------------------------------
      - 政府站點(diǎn) pythondv
  -------------------------------------
      - 我的站點(diǎn) pythonav
  
  這個(gè)解決方案:
    第一種:修改 pythondv 網(wǎng)站的請(qǐng)求方式,改成 script
    第二種:政府站點(diǎn)請(qǐng)求方式不用修改,在 pythonav 拿到數(shù)據(jù)返回的時(shí)候,加上響應(yīng)頭。
    
    
  一般就是你返回響應(yīng)頭,客戶端給你傳 cookie。

2. 解決跨域請(qǐng)求的兩種方式

  • jsonp
  • cors

3. 關(guān)于 jsonp

http://m.itdecent.cn/p/9b01fccf66b7

4. 關(guān)于 cors 跨域

隨著技術(shù)的發(fā)展,現(xiàn)在的瀏覽器可以主動(dòng)支持設(shè)置從而允許跨域請(qǐng)求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質(zhì)是設(shè)置響應(yīng)頭,使得瀏覽器允許跨域請(qǐng)求。
整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。

因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。

4.1 簡(jiǎn)單請(qǐng)求和復(fù)雜請(qǐng)求

條件:
    1、請(qǐng)求方式:HEAD、GET、POST
    2、請(qǐng)求頭信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 對(duì)應(yīng)的值是以下三個(gè)中的任意一個(gè)
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
 
注意:同時(shí)滿足以上兩個(gè)條件時(shí),則是簡(jiǎn)單請(qǐng)求,否則為復(fù)雜請(qǐng)求

4.2 兩者的區(qū)別

  • 簡(jiǎn)單請(qǐng)求: 一次請(qǐng)求
  • 非簡(jiǎn)單請(qǐng)求: 兩次請(qǐng)求,在發(fā)送數(shù)據(jù)之前會(huì)先發(fā)一次請(qǐng)求做'預(yù)檢',只有'預(yù)檢'通過(guò)后,才會(huì)再次發(fā)送一次請(qǐng)求用于數(shù)據(jù)傳輸。
    4.3 關(guān)于預(yù)檢
- 請(qǐng)求方式:OPTIONS *****
- “預(yù)檢”其實(shí)做檢查,檢查如果通過(guò)則允許傳輸數(shù)據(jù),檢查不通過(guò)則不再發(fā)送真正想要發(fā)送的消息
- 如何“預(yù)檢”
     > 如果復(fù)雜請(qǐng)求是PUT等請(qǐng)求,則服務(wù)端需要設(shè)置允許某請(qǐng)求,否則“預(yù)檢”不通過(guò)
        Access-Control-Request-Method
     > 如果復(fù)雜請(qǐng)求設(shè)置了請(qǐng)求頭,則服務(wù)端需要設(shè)置允許某請(qǐng)求頭,否則“預(yù)檢”不通過(guò)
        Access-Control-Request-Headers

4.4 關(guān)于 cors 的優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn): 可以發(fā)送任意請(qǐng)求,而 jsonp 只可以發(fā)送 get 請(qǐng)求。
  • 缺點(diǎn): 當(dāng)前請(qǐng)求如果是復(fù)雜請(qǐng)求的時(shí)候得先做個(gè)預(yù)檢,再發(fā)真實(shí)的請(qǐng)求。發(fā)送兩次請(qǐng)求可能會(huì)有性能上的損耗。

5. jsonp 和 cors 的區(qū)別。

JSONP:服務(wù)端不用修改,需要改前端。發(fā)jsonp請(qǐng)求

JSONP:只能發(fā)GET請(qǐng)求

CORS:前端的代碼不用修改,服務(wù)端的代碼需要修改。如果是簡(jiǎn)單請(qǐng)求的話在服務(wù)端加上一個(gè)響應(yīng)頭。

CORS:可以發(fā)任意請(qǐng)求

6. 基于 cors 實(shí)現(xiàn) ajax 請(qǐng)求

6.1 支持跨域,簡(jiǎn)單請(qǐng)求。

服務(wù)器設(shè)置響應(yīng)頭: Access-Control-Allow-Origin = '域名' 或 '*'
 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible"  content="IE=edge">
     <meta name="viewport" content="width=device-    width">
     <title>Title</title>
 </head>
 <div>
     <h1>welcome</h1>
     <button onclick="getData()">獲取用戶數(shù)據(jù)</button>
 </div>
 <script src="/static/jquery-1.12.4.min.js"></script>
 <script>
     function getData() {
         $.ajax({
             url:'http://127.0.0.1:8080/index/',
             type:"GET",
             success:function (data) {
                 console.log(data)
             }
 
         })
     }
 </script>
 </body>
 </html>
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.views import APIView 
# Create your views here.
class IndexView(APIView):
    def get(self,request,*args,**kwargs):
        ret = {
            'code': 100,
            'data': '777'
        }
        response = JsonResponse(ret)
        response['Access-Control-Allow-Origin'] = "*"
        return response

6.2 支持跨域,復(fù)雜請(qǐng)求。

  • 如果是復(fù)雜請(qǐng)求在你真正的發(fā)請(qǐng)求之前,會(huì)先偷偷的發(fā)一個(gè)OPTION請(qǐng)求,先預(yù)檢一下,我允許你來(lái)你才來(lái)。如果要想預(yù)檢通過(guò),就需要寫個(gè) option 請(qǐng)求。
由于復(fù)雜請(qǐng)求時(shí),首先會(huì)發(fā)送“預(yù)檢”請(qǐng)求,如果“預(yù)檢”成功,則發(fā)送真實(shí)數(shù)據(jù)。
  • “預(yù)檢”請(qǐng)求時(shí),允許請(qǐng)求方式則需服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Request-Method
  • “預(yù)檢”請(qǐng)求時(shí),允許請(qǐng)求頭則需服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Request-Headers
  • “預(yù)檢”緩存時(shí)間,服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Max-Age
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width">
    <title>Title</title>
</head>
<body>
<input type="button" value="獲取用戶數(shù)據(jù)" onclick="getUser()">
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
    function getUser() {
        $.ajax({
            url:'http://127.0.0.1:8080/user/',
            type:'POST',
            data:{'k1':'v1'},
            headers:{
                'h1':'777777'
            },
            success:function (ret) {
                console.log(ret)
            }
        })
    }
</script>
</body>
</html>

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView

class UserIndex(APIView):
    def get(self,request,*args,**kwargs):
        ret = {
            'code': 100,
            'data': 'ppp'
        }
        response = JsonResponse(ret)
        response['Access-Control-Allow-Origin'] = "*"
        return response

    def post(self,request,*args,**kwargs):
        print(request.POST.get('k1'))
        ret = {
            'code':101,
            'data':'fffff',
        }
        response = JsonResponse(ret)
        response['Access-Control-Allow-Origin'] = "*"
        return response

    def options(self, request, *args, **kwargs):
        # self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        # self.set_header('Access-Control-Allow-Headers', "k1,k2")
        # self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        # self.set_header('Access-Control-Max-Age', 10)
        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Headers'] = 'h1'
        # response['Access-Control-Allow-Methods'] = 'PUT'
        return response

6.3 跨域獲取響應(yīng)頭

  • 默認(rèn)獲取到的所有響應(yīng)頭只有基本信息,如果想要獲取自定義的響應(yīng)頭,則需要再服務(wù)器端設(shè)置Access-Control-Expose-Headers。
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                    // 獲取響應(yīng)頭
                    console.log(xhr.getAllResponseHeaders());
                }
            };
            xhr.open('PUT', "http://c2.com:8000/test/", true);
            xhr.setRequestHeader('k1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'PUT',
                dataType: 'text',
                headers: {'k1': 'v1'},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                    // 獲取響應(yīng)頭
                    console.log(xmlHttpRequest.getAllResponseHeaders());
                }
            })
        }


    </script>
</body>
</html>
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('xxoo', "seven")
        self.set_header('bili', "daobidao")
        self.set_header('Access-Control-Expose-Headers', "xxoo,bili")
        self.write('{"status": true, "data": "seven"}')

    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Headers', "k1,k2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)

6.4 跨域獲取 cookie

  • 在跨域請(qǐng)求中,默認(rèn)情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無(wú)論在預(yù)檢請(qǐng)求中或是在實(shí)際請(qǐng)求都是不會(huì)被發(fā)送。

如果想要發(fā)送:

  • 瀏覽器端:XMLHttpRequest的withCredentials為true
  • 服務(wù)器端:Access-Control-Allow-Credentials為true
  • 注意:服務(wù)器端響應(yīng)的 Access-Control-Allow-Origin 不能是通配符 *
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };

            xhr.withCredentials = true;
            xhr.open('PUT', "http://c2.com:8000/test/", true);
            xhr.setRequestHeader('k1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'PUT',
                dataType: 'text',
                headers: {'k1': 'v1'},
                xhrFields:{withCredentials: true},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }

    </script>
</body>
</html>
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Credentials', "true")
        self.set_header('xxoo', "seven")
        self.set_header('bili', "daobidao")
        self.set_header('Access-Control-Expose-Headers', "xxoo,bili")
        self.set_cookie('kkkkk', 'vvvvv');
        self.write('{"status": true, "data": "seven"}')

    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Headers', "k1,k2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容