同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。html
同源策略,它是由Netscape提出的一個著名的安全策略。如今全部支持JavaScript 的瀏覽器都會使用這個策略。所謂 同源是指,域名,協議,端口相同。當一個瀏覽器的兩個tab頁中分別打開來 百度和谷歌的頁面當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬於哪一個頁面的,即檢查是否同源,只有和百度同源的腳本纔會被執行。那麼在請求數據時,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>同源2</title> </head> <body> <h3>主頁</h3> <button class="get_service">點我</button> <script src="/static/jquery-3.3.1.js"></script> <script> $(".get_service").click(function () { $.ajax({ url:"http://127.0.0.1:8008/service/", // 注意 我請求的是另外一個服務器 success:function (data) { console.log(data); } }) }); </script>
項目二 view.py 端口 8008前端
from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return render(request,'index.html') import json def service(request): info = {"name": "yk", "age": 20} return HttpResponse(json.dumps(info))
當我點擊項目一 裏的 button 按鈕時,提示以下錯誤jquery
已攔截跨源請求:同源策略禁止讀取位於 http://127.0.0.1:8008/service/ 的遠程資源。(緣由:CORS 頭缺乏 'Access-Control-Allow-Origin')。
ajax
JSONP(JSON with Padding)是JSON的一種「使用模式」,可用於解決主流瀏覽器的跨域數據訪問的問題。其核心思想是利用JS標籤裏面的跨域特性進行跨域數據訪問,django
在JS標籤裏面存在的是一個跨域的URL,實際執行的時候經過這個URL得到一段字符串,這段返回的字符串必須是一個合法的JS調用,經過EVAL這個字符串來完成對得到的數據的處理。json
jsonp是json用來跨域的一個東西。原理是經過script標籤的跨域特性來繞過同源策略跨域
項目一 index.html 端口 8000瀏覽器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>同源2</title> </head> <body> <h3>主頁</h3>
<button class="get_service">點我</button> <script src="/static/jquery-3.3.1.js"></script> <script> function func(arg) { console.log(arg); console.log(typeof arg); data = JSON.parse(arg); console.log(data); console.log(typeof data); } </script> <script src="http://127.0.0.1:8008/service/"></script>
項目二 view.py 端口 8008安全
from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return render(request,'index.html') import json def service(request): info = {"name": "yk", "age": 20} return HttpResponse("func('%s')" % json.dumps(info))
當再次刷新index.htnl服務器
能夠見到,成功訪問到數據
項目一 index.html 端口 8000 點擊按鈕獲取數據
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>同源2</title> </head> <body> <h3>主頁</h3> <button class="get_service">點我</button> <script src="/static/jquery-3.3.1.js"></script> <script> function func(arg) { console.log(arg); console.log(typeof arg); data = JSON.parse(arg); console.log(data); console.log(typeof data); } </script> $(".get_service").click(function () {#} $(".get_service").click(function () { var ele_script = $("<script>"); ele_script.attr("src", "http://127.0.0.1:8008/service/"); ele_script.attr("id", "jsonp"); $("body").append(ele_script); $("#jsonp").remove();} ) </script>
項目一 index.html 端口 8000
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>同源2</title> </head> <body> <h3>主頁</h3> <button class="get_service">點我</button> <script src="/static/jquery-3.3.1.js"></script> <script> $(".get_service").click(function () { $.ajax({ url: "http://127.0.0.1:8008/service/", type: "get", dataType: "jsonp", //必須有,告訴server,此次訪問要的是一個jsonp的結果。 jsonp: "callbacks", //jQuery幫助隨機生成的:callbacks="jqueryxxxx"
// jsonpCallback:"SayHi" , // 若是指定 ,則回調函數名 爲SayHi
success: function (data) { console.log(data) } }) }) </script> </body> </html>
項目二 view.py 端口 8008
from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return render(request,'index.html') import json def service(request): func = request.GET.get("callbacks") # 獲取 回調函數名 info = {"name": "yk", "age": 20} return HttpResponse("%s('%s')" % (func,json.dumps(info)))
jsonp: 'callbacks'就是定義一個存放回調函數的鍵,jsonpCallback是前端定義好的回調函數方法名'SayHi',server端接受callback鍵對應值後就能夠在其中填充數據打包返回了;
jsonpCallback參數能夠不定義,jquery會自動定義一個隨機名發過去,那前端就得用回調函數來處理對應數據了。利用jQuery能夠很方便的實現JSONP來進行跨域訪問。
注意 JSONP必定是GET請求
CORS須要瀏覽器和服務器同時支持。目前,全部瀏覽器都支持該功能,IE瀏覽器不能低於IE10。
整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,
代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。
所以,實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。
支持跨域,簡單請求
服務器設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*'
支持跨域,複雜請求
因爲複雜請求時,首先會發送「預檢」請求,若是「預檢」成功,則發送真實數據。
def service(request): info={"name":"egon","age":34,"price":200} response=HttpResponse(json.dumps(info)) response["Access-Control-Allow-Origin"]="http://127.0.0.1:8008" # 設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*' #response["Access-Control-Allow-Origin"]="*" return response