同源策略
首先基於安全的原因,瀏覽器是存在同源策略這個機制的,同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。
而如果我們要跳過這個策略,也就是說非要跨域請求,那么就需要通過JSONP或者CORS來實現了。
JSONP
什么是JSONP
首先提一下JSON這個概念,JSON是一種輕量級的數據傳輸格式,被廣泛應用於當前Web應用中。JSON格式數據的編碼和解析基本在所有主流語言中都被實現,所以現在大部分前后端分離的架構都以JSON格式進行數據的傳輸。
那么JSONP是什么呢?
首先拋出瀏覽器同源策略這個概念,為了保證用戶訪問的安全,現代瀏覽器使用了同源策略,即不允許訪問非同源的頁面,詳細的概念大家可以自行百度。這里大家只要知道,在ajax中,不允許請求非同源的URL就可以了,比如www.a.com下的一個頁面,其中的ajax請求是不允許訪問www.b.com/c.php這樣一個頁面的。
JSONP就是用來解決跨域請求問題的,那么具體是怎么實現的呢?
JSONP原理
ajax請求受同源策略影響,不允許進行跨域請求,而script標簽src屬性中的鏈接卻可以訪問跨域的js腳本,利用這個特性,服務端不再返回JSON格式的數據,而是返回一段調用某個函數的js代碼,在src中進行了調用,這樣實現了跨域。
JSONP具體實現
127.0.0.1:8000中的index.html
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> $(".jsonp_test").click(function () { $.ajax({ url:"http://127.0.0.1:8008/service/", type:"get", dataType:"jsonp", // 偽造ajax 基於script jsonp: 'callbacks', //jsonpCallback:"alex", success:function (data) { console.log(data) } }) }) <button class='jsop_test'>測試</button> </body> </html>
127.0.0.1:8080的views
import json def jsonp_test(request): func=request.GET.get("callbacks") #獲取請求的callbacks參數 info={"name":"fuyong","age":18} #定義數據 return HttpResponse(" ('%s')"%(func,json.dumps(info))) #傳json對象
總結
一句話就是利用script標簽繞過同源策略,獲得一個類似這樣的數據。ajax里邊的callbacks本質上是(偽裝成script標簽src屬性發送請求的方式)發送一個回調方法,參數data就是想得到的json數據。
cors
CORS 定義
Cross-Origin Resource Sharing(CORS)跨來源資源共享是一份瀏覽器技術的規范,提供了 Web 服務從不同域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,是 JSONP 模式的現代版。與 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以讓網頁設計師用一般的 XMLHttpRequest,這種方式的錯誤處理比 JSONP 要來的好。另一方面,JSONP 可以在不支持 CORS 的老舊瀏覽器上運作。現代的瀏覽器都支持 CORS。
CORS 對比 JSONP
都能解決 Ajax直接請求普通文件存在跨域無權限訪問的問題
- JSONP只能實現GET請求,而CORS支持所有類型的HTTP請求
- 使用CORS,開發者可以使用普通的XMLHttpRequest發起請求和獲得數據,比起JSONP有更好的錯誤處理
- JSONP主要被老的瀏覽器支持,它們往往不支持CORS,而絕大多數現代瀏覽器都已經支持了CORS
CORS 實現思路
CORS背后的基本思想是使用自定義的HTTP頭部允許瀏覽器和服務器相互了解對方,從而決定請求或響應成功與否。
例如 localhost:63343 通過Ajax請求http://192.168.10.61:8080服務器資源時就會出現如下異常:
其實數據已經獲取到了,但是由於同源策略的限制給禁止了,提示說header里沒有Access-Control-Allow-Origin,那么,我們在發送響應的時候的只需要給header里加上這個參數就行了。
CORS的實現
CORS有很多種實現方式,這里介紹一種最簡單最直觀的的方式,就是修改views.py中對應函數,給它的響應頭部添加Access-Control-Allow-Origin餐具允許其他域通過Ajax請求數據,如下:
def cors_test(request): info={"name":"egon","age":34,"price":200} #數據 response=HttpResponse(json.dumps(info)) #序列化數據 #response["Access-Control-Allow-Origin"]="http://127.0.0.1:8006" #指定ip可訪問 #response["Access-Control-Allow-Origin"]="*"#所有ip均可訪問 return response #返回數據
實例
下面的代碼實現了通過添加中間件的方式實現跨域請求
cors.py
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response class CORSMiddleware(MiddlewareMixin): def process_response(self,request,response): # 添加響應頭 # 允許你的域名來獲取我的數據 response['Access-Control-Allow-Origin'] = "*" # 允許你攜帶Content-Type請求頭 response['Access-Control-Allow-Headers'] = "Content-Type" # 允許你發送DELETE,PUT response['Access-Control-Allow-Methods'] = "DELETE,PUT" return response
settings.py
MIDDLEWARE = [ ..... 'xxx.cors.CORSMiddleware', # xxx為cors.py所在包的目錄 ]