同源策略
同源策略是瀏覽器的一個安全策略,只允許當前頁面或當前域下發送請求,如果向其他域發送請求,會被瀏覽器攔截
同源的意思:協議、IP地址、端口三者一致,瀏覽器才會認為是同一個域,三者中有一個不一致就是不同域
實例:比如說我們要通過127.0.0.1:8001/test/中的一個點擊事件,提交一個ajax請求,要去拿127.0.0.1:8010/test2/的返回數據,這時候就會遇到一個問題——跨域資源共享的問題,程序的報錯信息如下:
Access to XMLHttpRequest at 'http://127.0.0.1:8010/test2/' from origin 'http://127.0.0.1:8001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. # CORS策略已阻止從源站“http://127.0.0.1:8001”訪問位於“http://127.0.0.1:8010/test2/”的xmlhttpRequest:請求的資源上不存在“訪問控制允許源站”頭
views.py(該程序運行的網址為http://127.0.0.1:8010/test2)
from django.shortcuts import render, HttpResponse def test2(request): return HttpResponse('這是另一個網站地址')
在127.0.0.1:8001/test/中通過ajax向127.0.0.1:8010/test2/發送GET請求,其實數據已經被拿回來了,報錯的原因就是返回的數據被瀏覽器攔截了,這就是跨域問題的本質。那如何解決這個問題,最簡單的處理方法就是在被ajax請求訪問的視圖函數返回的時候讓它帶上一個參數:response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8001'
將8010端口運行的views.py做如下修改
def test2(request): response = HttpResponse('這是另一個網站地址') # 只允許一個域 response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001' # 允許所有的域 # response['Access-Control-Allow-Origin'] = '*' return response
這時候再去通過ajax訪問127.0.0.1:8010/test2/網站就不會報錯了!執行效果如下:
其實,CORS有兩種請求方式,以上處理的這只是簡單請求
簡單請求與非簡單請求
簡單請求必須滿足的條件
# 1、請求方法是以下一種: GET POST HEAD # 2、http的頭信息不超出以下幾種: Accept Accept-Language Content-Language Last-Event-ID Content-Type:application/x-www-form-urlencoded、multipart/form-data、text/plain # 只限於這三個值
除了以上的所有出現的信息都是非簡單請求!
那針對不同的請求會有不同的解決方法,所謂的簡單請求就是只發送一次請求,而非簡單請求是發送兩次請求,在發送數據之前會先發一次請求用於做“預檢(OPTIONS)”,只有“預檢”通過后才再發送一次請求用於數據傳輸
預檢
請求方式:OPTIONS
“預檢”其實是做檢查,檢查如果通過則允許傳輸數據,檢查不通過則不再發送真正想要發送的消息
如何“預檢”
如果復雜請求是PUT等請求,則服務端需要設置允許某請求,否則“預檢”不通過
Access-Control-Request-Method
如果復雜請求設置了請求頭,則服務端需要設置允許某請求頭,否則“預檢”不通過
Access-Control-Request-Headers
簡單請求支持跨域
服務器設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*'
非簡單請求支持跨域
由於復雜請求時,首先會發送“預檢”請求,如果“預檢”成功,則發送真實數據。
- “預檢”請求時,允許請求方式則需服務器設置響應頭:Access-Control-Request-Method
- “預檢”請求時,允許請求頭則需服務器設置響應頭:Access-Control-Request-Headers
在Django中解決CORS問題
可以通過上述方法在返回的結果中添加允許信息來解決簡單請求,還可以在Django的中間件中處理簡單請求和非簡單請求
from django.utils.deprecation import MiddlewareMixin class CorsMiddleWare(MiddlewareMixin): def process_response(self,request,response):
# 非簡單請求 if request.method=="OPTIONS": #可以加* response["Access-Control-Allow-Headers"]="Content-Type" response["Access-Control-Allow-Origin"] = "允許訪問的URL" return response