同源策略 - JSONP - CORS

 

 

1.  Jquery 對象能夠經過 .index() 進行取出自當前元素在父級元素中存放的索引;javascript

2. 瀏覽器的同源策略 -- Ajax 在訪問非本網站的時候,在數據返回的時候,會被瀏覽器攔截html

   - 後端使用 requests 獲取數據後,發送給前端前端

   - jsonp 在前端頁面中, 帶有 src 屬性的標籤不受同源策略的影響(img, script, iframe等),咱們能夠經過使用 script 標籤來獲取內容,但 script 中 src 獲取內容後,得到到的字符串(相似於調用python中的 eval 或 exec)會被 JS 執行,因此咱們能夠定義一個函數,而後讓服務端返回的內容外面包裹一層這個函數名,前端在訪問的時候把這個函數名發送過去,並提早定義好該函數java

手動實現:

服務端返回的數據python

 

def server(request):

    return HttpResponse("aaa('important data!!!')")

 

客戶端定義及獲取數據jquery

<!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, initial-scale=1">
    <title>Client</title>
    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        $(function(){

        });

        var url = 'http://127.0.0.1:8000/server.html/';  // 服務端路徑
        var $script;                                     // 模擬使用建立的標籤名
        function aaa(data){                              // 數據返回後用來接收的函數
            alert(data);
            document.head.removeChild($script);          // 接收完數據後,從頁面刪除剛纔使用的標籤
        }
        function getInfo(){
            $script = document.createElement("script");  // 建立一個 script 標籤
            $script.setAttribute("src", url);            // 將須要請求數據的地址放入 script 的 src 中
            document.head.appendChild($script);          // 將標籤放入到 head 中

        }

    </script>
</head>
<body>
    <h1>Client</h1>
    <input type="button" onclick="getInfo()" value="getInfo">
</body>
</html>

 

經過JSONP自動完成 - 上面是它的原理

 

 服務端返回的數據web

from django.shortcuts import render
from django.http import HttpResponse, JsonResponse

def server(request):
    # 根據後端發送過來的名字來決定返回時,數據外面套的內容
    funcName = request.GET.get("callback")
    return HttpResponse("%s('important data!!!')"%funcName)

  客戶端定義及獲取數據ajax

<!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, initial-scale=1">
    <title>Client</title>
    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function bbb(data){
            alert(data);
        }

        $(function(){
            var url = 'http://127.0.0.1:8000/server.html/';  // 服務端路徑
            $.ajax({
                url: url,                   // 跨站請求數據的路徑
                type: 'GET',                // 發送方式爲 get, 因爲使用的是 script, 因此只支持 get
                dataType: 'JSONP',          // 使用 JSONP 方式
                jsonp: 'callback',          // get 發送的時候,後面跟的數據名爲 callback
                jsonpCallback: 'bbb'        // get 發送數據的callback的值爲 bbb
            })
        });

    </script>
</head>
<body>
    <h1>Client</h1>
    <input type="button" value="getInfo">
</body>
</html>

 

cors - 跨域資源共享 cross origin resource sharing

隨着技術的發展,如今的瀏覽器能夠支持主動設置從而容許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,使得瀏覽器容許跨域請求。django

  cors 分爲簡單請求和非簡單請求,簡單請求只發送一次,直接發送數據,非簡單請求則會發送兩次數據,第一次發送 opption 請求(預檢),爲的是查看真正的數據是否能夠被接收(數據頭和請求方式是否符合要求), 若是符合要求,服務端能夠把內容加入到頭文件中來告訴瀏覽器;json

簡單請求與非簡單請求

條件:
    一、請求方式:HEAD、GET、POST
    二、請求頭信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 對應的值是如下三個中的任意一個
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
 
注意:同時知足以上兩個條件時,則是簡單請求,不然爲複雜請求

  

關於預檢

- 請求方式:OPTIONS
- 「預檢」其實作檢查,檢查若是經過則容許傳輸數據,檢查不經過則再也不發送真正想要發送的消息
- 如何「預檢」
     => 若是複雜請求是PUT等請求,則服務端須要設置容許某請求,不然「預檢」不經過
        Access-Control-Request-Method
     => 若是複雜請求設置了請求頭,則服務端須要設置容許某請求頭,不然「預檢」不經過
        Access-Control-Request-Headers

  

簡單請求:在使用cors的時候,客戶端幾乎不用修改,只須要按照普通的ajax的請求方式發送,在服務端返回數據的時候,只要在返回的時候,加上一個響應頭就能夠解決這個問題了

def example(request):
    response = HttpResponse("返回的數據內容")
    response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8888"  # 容許訪問獲取信息的域名
    return response

  服務器設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*',容許訪問獲取信息的域名,若是後面是*的話,表明容許全部的請求,若是須要每個相應都設置該響應頭的話(即這個網站的全部資源均可以被其它域名的所訪問,那麼咱們能夠在中間件中設置這個響應頭);

 

對於複雜請求,會先發一次預檢(OPTIONS)請求,若是服務端容許,那麼再發送一次正式請求(如PUT等,總之就是正真的請求),這個時候,咱們須要在後端進行判斷,若是容許用戶獲取數據,那麼當預檢(OPTIONS)過來的時候,咱們須要返回容許訪問的請求:Access-Control-Allow-Methds

if request.method == "OPTIONS":
    response = HttpResponse() // 返回的內容能夠爲空,主要須要返回請求頭
    response['Access-Control-Allow-Origin'] = '*'
    response['Access-Control-Allow-Methods'] = 'PUT'   # 容許的複雜請求方式爲 PUT 請求;若是多個,用逗號分隔, "PUT, DELETE"
    response['Access-Control-Allow-Headers'] = "k1"  # 複雜請求還有一種狀況就是定製請求頭,這種狀況下,咱們在返回的相應中應該設置該響應頭,表明容許發送請求頭的key是什麼,若是多個,逗號分隔 "k1, k2"
    return response

  若是咱們不想每次都通過「預檢」這個環節的話,那麼咱們能夠在服務器的響應頭中增長一組:Access-Control-Max-Age的響應頭,能夠寫成

response['Access-Control-Allow-Headers'] = 10  # 默認單位爲秒

  

 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, initial-scale=1">
 7     <title>Title</title>
 8     <script src="/static/jquery-3.2.1.js"></script>
 9     <script>
10         $(function(){
11             $("#btn01").click(function(){
12                 $.ajax({
13                     url: "http://127.0.0.1:8000/btn01/",
14                     success: function(data){
15                         console.log(data)
16                     }
17                 })
18             });
19 
20             $("#btn02").click(function(){
21                 $.ajax({
22                     url: "http://127.0.0.1:8000/btn02/",
23                     type: "PUT",
24                     success: function(data){
25                         console.log(data)
26                     }
27                 })
28             });
29 
30             $("#btn03").click(function(){
31                 $.ajax({
32                     url: "http://127.0.0.1:8000/btn03/",
33                     headers: {"k1": "asdfasdf"},
34                     success: function(data){
35                         console.log(data)
36                     }
37                 })
38             })
39         })
40     </script>
41 </head>
42 <body>
43 <p><input type="button" value="簡單請求" id="btn01"></p>
44 <p><input type="button" value="複雜請求-PUT" id="btn02"></p>
45 <p><input type="button" value="複雜請求-Headers" id="btn03"></p>
46 </body>
47 </html>
簡單和複雜請求的客戶端代碼
 1 from django.shortcuts import render
 2 from django.http import HttpResponse
 3 
 4 # Create your views here.
 5 def btn01(request):
 6     response = HttpResponse("btn01")
 7     response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8888"
 8     return response
 9 
10 
11 def btn02(request):
12     if request.method == "OPTIONS":
13         response = HttpResponse()
14         response['Access-Control-Allow-Origin'] = '*'
15         response['Access-Control-Allow-Methods'] = 'PUT'
16         return response
17 
18     if request.method == "PUT":
19         response = HttpResponse("btn02")
20         response['Access-Control-Allow-Origin'] = '*'
21         return response
22 
23 
24 def btn03(request):
25     if request.method == "OPTIONS":
26         response = HttpResponse()
27         response['Access-Control-Allow-Origin'] = '*'
28         response['Access-Control-Allow-Headers'] = "k1"
29         return response
30 
31     if request.method == "GET":
32         response = HttpResponse("btn03")
33         response['Access-Control-Allow-Origin'] = '*'
34         return response
簡單和複雜請求的服務端代碼

 

 

攜帶cookie的傳輸

若是在使用Ajax請求的時候,須要傳遞cookie的時候,咱們則須要在發送ajax的時候,以及服務器給咱們相應的時候加上一組頭信息

客戶端須要加:XMLHttpRequest的withCredentials爲true

$.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);
    }
})

  

服務端須要加:Access-Control-Allow-Credentials爲true

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)

  

 

http://www.cnblogs.com/wupeiqi/articles/5703697.html

 

3. 模擬點擊事件

$("#a").trigger("chick"); // 模擬執行 id=a 的事件

相關文章
相關標籤/搜索