同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。css
同源策略,它是由Netscape提出的一個著名的安全策略。如今全部支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,域名,協議,端口相同。當一個瀏覽器的兩個tab頁中分別打開來 百度和谷歌的頁面當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬於哪一個頁面的,即檢查是否同源,只有和百度同源的腳本纔會被執行。若是非同源,那麼在請求數據時,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。html
• 源(origin)就是指的協議、域名和端口號。
以上url中的源就是:http://www.company.com:80
若地址裏面的協議、域名和端口號均相同則屬於同源。
如下是相對於 http://www.a.com/test/index.html 的同源檢測
• http://www.a.com/dir/page.html ----成功
• http://www.child.a.com/test/index.html ----失敗,域名不一樣
• https://www.a.com/test/index.html ----失敗,協議不一樣
• http://www.a.com:8080/test/index.html ----失敗,端口號不一樣python
同源策略是瀏覽器的一個安全功能,不一樣源的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方資源。因此a.com下的js腳本採用ajax讀取b.com裏面的文件數據是會報錯的。jquery
• 不受同源策略限制的:
一、頁面中的連接,重定向以及表單提交是不會受到同源策略限制的。
二、跨域資源的引入是能夠的。可是js不能讀寫加載的內容。如嵌入到頁面中的<script src="..."></script>,<img>,<link>,<iframe>等。ajax
受前面所講的瀏覽器同源策略的影響,不是同源的腳本不能操做其餘源下面的對象。想要操做另外一個源下的對象是就須要跨域。django
• 降域 document.domain
同源策略認爲域和子域屬於不一樣的域,如:
child1.a.com 與 a.com,
child1.a.com 與 child2.a.com,
xxx.child1.a.com 與 child1.a.com
兩兩不一樣源,能夠經過設置 document.damain='a.com',瀏覽器就會認爲它們都是同一個源。想要實現以上任意兩個頁面之間的通訊,兩個頁面必須都設置documen.damain='a.com'。
此方式的特色:
1. 只能在父域名與子域名之間使用,且將 xxx.child1.a.com域名設置爲a.com後,不能再設置成child1.a.com。
2. 存在安全性問題,當一個站點被攻擊後,另外一個站點會引發安全漏洞。
3. 這種方法只適用於 Cookie 和 iframe 窗口。
• JSONP跨域
JSONP和JSON並無什麼關係!
JSONP的原理:(舉例: http://127.0.0.1:8001/想獲得 http://127.0.0.1:8002/中的數據)在a.com的jsonp.html裏建立一個回調函數xxx,動態添加<script>元素,向服務器發送請求,請求地址後面加上查詢字符串,經過callback參數指定回調函數的名字。請求地址爲 http://127.0.0.1:8001?callback=xxx。在main.js中調用這個回調函數xxx,而且以JSON數據形式做爲參數傳遞,完成回調。json
如今咱們看看 http://127.0.0.1:8001/的html代碼:跨域
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <p>這是首頁!</p> <button>提交</button> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> $("button").click(function () { alert(123) $.ajax({ url: "http://127.0.0.1:8002//test/", success: function (data) { console.log(data) } }) }) </script> </body> </html>
在這個代碼裏面調用了8002的資源。瀏覽器
8802:的views代碼:安全
from django.shortcuts import render, HttpResponse # Create your views here. def test(request): print("會出現嗎。非常期待哦") return HttpResponse("this is test")
這是一個簡單的調用。你會發現。瀏覽器不容許你進行調用。
由於控制檯已經給你調用了
說明是瀏覽器不容許你進行跨域.
可是大家發現沒有。一樣是跨域調用。我進行jquery的cdn調用就不會進行攔截。
看到這裏你的內心難道就沒有點想法嗎?
沒有,既然不給我進行js的跨域,那我跨域假裝成上面的那種方式進行調用呀!說幹就幹,擼起手就是幹。
8001的HTML代碼如圖:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <p>這是首頁!</p> {#{% csrf_token %}#} <button>提交</button> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> $("button").click(function () { var html_script = $("<script>"); html_script.attr("src","http://127.0.0.1:8002/test/"); html_script.attr("id","test"); $("body").append(html_script); $("#test").remove();//生成的標籤調用完畢,立刻移除掉。 }) function get_data(test2_data) { console.log(test2_data) } </script> </body> </html>
8002 的views代碼:
from django.shortcuts import render, HttpResponse # Create your views here. def test(request): print("會出現嗎。非常期待哦") return HttpResponse("get_data('ok')") # 傳遞一個跟8001同名的get_data()函數
這樣調用跨域的資源就不會出錯了。
。如今爲了更加靈活,如今將在客戶端定義的回調函數傳送給服務端。服務端就會返回逸直接定義的回調函數名的方法。將獲取的json數據傳入這個方法就能夠完成回調了。
8001代碼也就是客戶端代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <p>這是首頁!</p> {#{% csrf_token %}#} <button>提交</button> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> $("button").click(function () { var html_script = $("<script>"); html_script.attr("src","http://127.0.0.1:8002/test/?callbacks=get_data"); html_script.attr("id","test"); $("body").append(html_script); $("#test").remove();//生成的標籤調用完畢,立刻移除掉。 }) function get_data(test2_data) { console.log(test2_data) } </script> </body> </html>
8002也就是服務端只需這樣調用便可:
from django.shortcuts import render, HttpResponse import json # Create your views here. def test(request): print("會出現嗎。非常期待哦") func = request.GET.get("callbacks") print(func) a_dict = {"key": "values"} return HttpResponse("%s(%s)" % (func, json.dumps(a_dict))) # 須要把數據進行序列化方能夠傳遞過去
讓咱們來看看結果唄
這就跨域調用數據成功了。
jQuery中的Jsonp方法
只須要改動8001中的html代碼便可:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <p>這是首頁!</p> {#{% csrf_token %}#} <button>提交</button> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> $("button").click(function () { f("http://127.0.0.1:8002/test/") }) function f(url) { $.ajax({ url: url, dataType:"jsonp", jsonp: 'callbacks', //這裏的值(callbacks)至關於url中的建的名字 jsonpCallback: 'ok', // 這裏的值(ok)至關於回調函數的函數名,也就是url中的值 success:function (data) { console.log(data) } }); } </script> </body> </html>
你能夠正常的跨域調用。
可是上面的代碼有個能夠不用有:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <p>這是首頁!</p> {#{% csrf_token %}#} <button>提交</button> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> $("button").click(function () { f("http://127.0.0.1:8002/test/") }) function f(url) { $.ajax({ url: url, dataType:"jsonp", jsonp: 'callbacks', //這裏的值(callbacks)至關於url中的建的名字 //jsonpCallback: 'ok', // 這裏的值(ok)至關於回調函數的函數名,也就是url中的值 success:function (data) { console.log(data) } }); } </script> </body> </html>
從這裏能夠看出不必定須要本身定義回調函數名也能夠,jsonp也能夠幫你生成函數名: