同源策略

同源策略

  • 同源策略是瀏覽器的一個安全功能,不一樣源的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方資源。因此xyz.com下的js腳本採用ajax讀取abc.com裏面的文件數據是會被拒絕的。
  • 同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。
  • 已經接收到了請求並返回了響應,是瀏覽器對非同源請求返回的結果作了攔截

1、源的定義

  • 若是兩個頁面的協議,端口(若是有指定)和域名都相同,則兩個頁面具備相同的源。
  • 下表給出了相對http://a.xyz.com/dir/page.html同源檢測的示例:
URL 結果 緣由
http://a.xyz.com/dir2/other.html 成功  
http://a.xyz.com/dir/inner/another.html 成功  
https://a.xyz.com/secure.html 失敗 不一樣協議 ( https和http )
http://a.xyz.com:81/dir/etc.html 失敗 不一樣端口 ( 81和80)
http://a.opq.com/dir/other.html 失敗 不一樣域名 ( xyz和opq)

2、不受同源策略限制的

  • 頁面中的連接,重定向以及表單提交是不會受到同源策略限制的。
  • 2. 跨域資源的引入是能夠的。可是js不能讀寫加載的內容。如嵌入到頁面中的<script src="..."></script>,<img>,<link>,<iframe>等。

3、JSONP解決跨域問題

  • JSONP的原型:建立一個回調函數,而後在遠程服務上調用這個函數而且將JSON 數據形式做爲參數傳遞,完成回調。
  • 將JSON數據填充進回調函數,這就是JSONP的JSON+Padding的含義。
<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">點我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
  function rion(res) {
    console.log(res);
  }

  function addScriptTag(src) {
    var scriptEle = document.createElement("script");
    $(scriptEle).attr("src", src);
    $("body").append(scriptEle);
    $(scriptEle).remove();
  }
  $("#b1").click(function () {
    addScriptTag("http://127.0.0.1:8002/abc/?callback=rion")
  });
</script>
</body>
</html>
html
def abc(request):
    res = {"code": 0, "data": ["SNIS-561", "SNIS-517", "SNIS-539"]}
    func = request.GET.get("callback")
    return HttpResponse("{}({})".format(func, json.dumps(res)))
view
<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">點我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
  $("#b1").click(function () {
    $.getJSON("http://127.0.0.1:8002/abc/?callback=?", function (res) {
      console.log(res);
    })
  });

  //要注意的是在url的後面必需要有一個callback參數,這樣getJSON方法纔會知道是用JSONP方式去訪問服務,
  // callback後面的那個?是jQuery內部自動生成的一個回調函數名。
</script>
</body>
</html>
jQuery中getJSON方法
<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">點我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
  $("#b1").click(function () {
    $.ajax({
      url: "http://127.0.0.1:8002/abc/",
      dataType: "jsonp",
      jsonp: "callback",
      jsonpCallback: "rion2"  //若是服務端規定了回調函數名,可使用$.ajax方法來實現:
    })
  });
  function rion2(res) {
    console.log(res);
  }


  //不過一般都會將回調函數寫在success回調中:

   $("#b1").click(function () {
    $.ajax({
      url: "http://127.0.0.1:8002/abc/",
      dataType: "jsonp",
      success: function (res) {
        console.log(res);
      }
    })
  })

</script>
</body>
</html>
ajax

4、CORS解決跨域問題

  • CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它容許瀏覽器向跨源服務器發出XMLHttpRequest請求,從而解決AJAX只能同源使用的限制。
  • CORS須要瀏覽器和服務器同時支持。目前基本上主流的瀏覽器都支持CORS。因此只要後端服務支持CORS,就可以實現跨域。
  • 瀏覽器將CORS請求分紅兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。

一、簡單請求

一個請求須要同時知足如下兩大條件才屬於簡單請求。css

(1) 請求方法是如下三種方法之一:
    HEAD
    GET
    POST

(2)HTTP的頭信息不超出如下幾種字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

二、簡單請求的處理方式

在跨域場景下,當瀏覽器發送簡單請求時,瀏覽器會自動在請求頭中添加代表請求來源的 Origin 字段。html

後端程序只須要在返回的響應頭中加上 Access-Control-Allow-Origin 字段,而且把該字段的值設置爲 跨域請求的來源地址或簡單的設置爲 * 就能夠了。jquery

例如:能夠在Django中間件中的process_response方法來給相應對象添加該字段。git

from django.utils.deprecation import MiddlewareMixin

class CorsMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
        # 給響應頭加上 Access-Control-Allow-Origin 字段 並簡單的設置爲 *
        response['Access-Control-Allow-Origin'] = '*'
        return response
process_response

三、非簡單請求的處理方式

  • 開發中經常使用到的那些請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json的都是非簡單請求。
  • 對於非簡單請求,瀏覽器一般都會在請求以前發送一次 OPTIONS 預檢 請求。該請求會像後端服務詢問是否容許從當前源發送請求而且詢問容許的 請求方法 和 請求頭字段。

解決辦法:能夠在後端簡單的給響應對象添加上 經常使用請求方法(PUT、DELETE)的支持就能夠了。github

from django.utils.deprecation import MiddlewareMixin


class CorsMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
        # 給響應頭加上 Access-Control-Allow-Origin 字段 並簡單的設置爲 *
        response['Access-Control-Allow-Origin'] = '*'
        if request.method == 'OPTIONS':
            # 容許發送 PUT 請求
            response['Access-Control-Allow-Methods'] = 'PUT, DELETE'
            # 容許在請求頭中攜帶 Content-type字段,從而支持發送json數據
            response['Access-Control-Allow-Headers'] = 'Content-type'
        return response
process_response

5、使用django-cors-headers跨域

上面中間件確實能解決目前的CORS跨域問題,可是不夠嚴謹,已經有人造好輪子-- django-cors-headers 了。 更多詳細配置詳細請查看django-cors-headers項目ajax

1.安裝
    pip install django-cors-headers
2.註冊APP

    INSTALLED_APPS = [
        ...
        'app01.apps.App01Config',
        'corsheaders',  # 將 corsheaders 這個APP註冊
    ]
3.添加中間件
    必須放在最前面,由於要先解決跨域的問題。只有容許跨域請求,後續的中間件纔會正常執行。

    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',  # 添加中間件
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

4.配置
    #能夠選擇不限制跨域訪問
    CORS_ORIGIN_ALLOW_ALL = True

    # 或者能夠選擇設置容許訪問的白名單
    CORS_ORIGIN_ALLOW_ALL = False
    CORS_ORIGIN_WHITELIST = (
        # '<YOUR_DOMAIN>[:PORT]',
        '127.0.0.1:8080'
    )
django-cors-headers 配置
相關文章
相關標籤/搜索