跨域html
跨域指的就是「跨域資源共享(Cross-Origin Resource Sharing, CORS)」,是一個「W3C標準」,當一個資源從與該資源自己所在的服務器的不一樣域或者不一樣端口請求一個資源時,就會發起一個跨域HTTP請求。git
說到跨域,確定就要講一下 同源策略(Same origin policy),該策略是由Netscape(網景)公司在1995年引入瀏覽器的一個著名的安全策略,是一種約定,也是瀏覽器最核心,最基本的安全功能,若是少了同源策略,瀏覽器的正常功能可能都會收到影響,能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。目前全部支持JavaScript的瀏覽器都會使用這個策略。github
同源的目的正則表達式
爲了保證用戶信息的安全,防止惡意網站竊取數據
設想這樣一種狀況:A網站是一家銀行,用戶登陸後,產生了Cookie,在沒有同源策略的狀況下,又去瀏覽其餘網站,則其餘網站能夠讀取到A網站的Cookie,會發生什麼?很顯然,若是Cookie 包含隱私(好比存款總額)這些信息就會泄露,更可怕的是,Cookie每每用來保存用戶的登陸狀態,若是用戶沒有退出登陸,其餘網站就能夠冒充用戶,隨心所欲。
因此同時打開的B網頁,不能訪問A頁的Cookie,除非這兩個網頁「同源」,若是非同源,那麼請求數據的時候,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。
django
什麼是同源json
協議相同:好比http://
域名相同:好比「www.test.com」
端口相同:好比同爲8000(默認端口80能夠省略)
同時知足知足以上三個條件的才能夠被稱爲同源後端
舉例說明:http://www.example.com/dir/page.html 這個網址,協議是http://, 域名是www.example.com,端口是80(默認端口能夠省略),它的同源狀況以下:api
A.http://www.example.com/dir2/other.html 同源
B.http://www.example.cn/dir/other.html 不一樣源(域名不一樣)
C.http://example.com/dir/other.html 不一樣源(域名不一樣)
D.http://v2.www.example.com/dir/other.html 不一樣源(域名不一樣)
E.http://www.example.com:81/dir/other.html 不一樣源(端口不一樣)跨域
非同源的限制瀏覽器
1.Cookie、LocalStorage、IndexDB 沒法讀取
2.DOM 沒法得到
3.AJAX 請求不能發送
因爲本文主要是介紹Django目前最優的解決跨域請求的方法,對避免上述三種限制有興趣的小夥伴能夠去阮老師的《瀏覽器同源策略及其規避方法》的http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
迴歸Django的跨域的解決方案
參考資料:https://github.com/ottoyiu/django-cors-headers/
原做者測試的組合:
Python:2.七、 3.6
Django:1.八、1.九、1.十、1.十一、2.0、2.1
我所使用的組合:
Python:3.6 Django:1.11.11
具體步驟:
1.pip 安裝:
在所使用的虛擬環境中安裝:
pip install django-cors-headers
2.將其註冊到Django 項目setting的INSTALLED_APPS中:
INSTALLED_APPS = (
...,
'corsheaders',
...
)
3.添加中間件類來監聽響應
# ‘CorsMiddleware’ 圖省事能夠放在最外層
推薦儘量放置在生成響應的任何中間件以前,
如Django 'CommonMiddleware' ,若是不是,則會跨域失敗
MIDDLEWARE = [
...,
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
4.須要在Django中使用的配置
CORS_ORIGIN_WHITELIST
容許白名單,容許執行跨站請求的主機列表(疑問添加'null',待解決),默認是:[ ]
如:
CORS_ORIGIN_WHITELIST = (
'12.0.0.1:8000',
'google.com',
'localhost:8000',
)
CORS_ALLOW_CREDENTIALS
跨域請求時是否容許攜帶Cookie,默認是False
CORS_ALLOW_CREDENTIALS = True
# 實現以上配置功能便可進行跨域
# 配置擴展(如下配置,根據需求進行添加)
CORS_ORIGIN_ALLOW_ALL
若是是True,將再也不使用白名單,並容許全部主機執行跨站點請求,默認是False
CORS_ORIGIN_REGEX_WHITELIST
當你有大量子域名須要添加到白名單的時候,‘CORS_ORIGIN_WHITELIST’ 就不太適用了,能夠經過此設置將對HTTP請求進行正則匹配,匹配成功則容許跨域,不然不容許,默認是[ ]
如:
CORS_ORIGIN_REGEX_WHITELIST = (
r'^(https?://)?(\w+\.)?google\.com$',
r'^(https?://)?(\w+\.)?baidu\.com$',
)
CORS_URLS_REGEX
一個正則表達式,限制全部進行CORS 的URL,默認是 r'^.*' 即匹配全部URL,當您只須要一部分請求CORS時,頗有用,例如API /api/:
CORS_URLS_REGEX = r"^/api/.*$"
CORS_ALLOW_METHODS
容許跨域的請求方式,通常使用默認,以下:
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
)
擴展添加額外的請求方式時能夠導入默認值,如:
from corsheaders.defaults import default_methods
CORS_ALLOW_METHODS = default_methods + (
'POKE' # 自定義請求方式
)
CORS_ALLOW_HEADERS
容許跨域的請求頭,通常使用默認值,如:
CORS_ALLOW_HEADERS = (
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
)
同上同樣,能夠導入默認值,來實現自定義請求頭的擴展
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = default_headers + (
'my-custom-header',
)
CORS_EXPOSE_HEADERS
向瀏覽器公開的HTTP請求頭列表,默認是 [ ]
CORS_MODEL
幾乎用不到,留坑,之後擴展。默認爲None
CORS_PREFLIGHT_MAX_AGE
瀏覽器或者客戶端能夠緩存預檢響應的秒數,若是是0或者任何假值,則再次發送請求時,還須要進行預檢,默認是86400(一天)
擴展:預檢是發送「非簡單請求」時,發送真正請求前的額外請求
簡單請求與非簡單請求
同時知足如下兩大條件,就屬於簡單請求,不然就是複雜請求
1、請求方式
1.HEAD
2.GET
3.POST
2、請求頭信息
1.Accept
2.Accept-Language
3.Content-Language
4.Last-Event-ID
5.Content-Type 只限於三個值:application/x-www-form-urlencoded、multipart/form-data、text/plain
針對簡單請求和複雜請求,瀏覽器的處理方式
簡單請求
瀏覽器直接發出CORS 請求 ,具體來講就是在請求頭信息中添加一個"Origin"的字段
Origin字段的做用,就是說明本次請求來自哪一個源(協議+域名+端口),服務器根據這個值,決定是否贊成此次請求
1.若是Origin指定的源不在許可範圍內,服務器會返回一個頭信息裏面不包含「Access-Control-Allow-Origin」字段的正常響應,瀏覽器發現沒有該字段後,就會拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。注意,由於這種HTTP迴應的狀態碼多是200,因此沒法經過狀態碼識別或進行條件判斷。
2.若是Origin指定的源在許可範圍內,服務器的返回的響應裏面,會多出四個頭信息字段,其中三個字段與CORS請求相關,且都是以「Access-Control-」 開頭
Access-Control-Allow-Origin
該字段是必須的,它的值要麼是請求時Origin字段的值,要麼時一個「*」,表示接收任意域名的請求
Access-Control-Allow-Credentials
該字段可選,值是一個布爾值,表示是否容許發送Cookie,默認爲False
若是須要將Cookie 包含在請求頭中,一塊兒發給服務器,則必須將此字段設爲True
Access-Control-Expose-Headers
該字段可選,CORS請求時,XMLHttpRequest 對象的getResponseHeader()方法只能拿到6個基本字段「Cache-Control(緩存控制)」,「Content-Language(指明報文體使用的語言,譬如:ch,fr,en,ja等等)」,「Content-Type(指定報文體的類型,好比text/xml,image/jpeg等等,同時能夠經過charset來指定內容所使用的字符集)」,「Expires(用來控制緩存的失效期,若是Cache-Control設置「max-age」或"s-max-age",則會忽略該字段)」,「Last-Modified(請求成功後用來標記此文件在服務器端最後被修改的時間,若是第二次進行請求發現服務器資源沒有發生變化,此字段值不變,則自動重定向並返回304(Not Changed)的狀態碼)」,「Pragma(HTTP/1.0時功能比較弱的緩存機制,HTTP/1.0存在該字段時會忽略「Expires」和「Cache-control」字段)」,若是但願該方法能拿到其餘字段,就必需要在‘Access-Control-Expose-Headers’中指定
非簡單請求
對服務器又特殊要求的請求,常見的如請求方式時「PUT」或"DELETE",或者請求頭Content-Type字段的類型是application/json時
非簡單請求的CORS請求,會在正式通訊前,增長一次HTTP查詢請求,稱爲「預檢(preflight)」請求
預檢其實就是作檢查,檢查若是經過則容許傳輸數據,檢查不經過則不能發送真正要發送的消息
預檢的請求方式:OPTIONS, 表示這個請求時用來詢問的
預檢的請求頭信息的關鍵字段
Origin
表示請求來自哪一個源
Access-Control-Request-Method
該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些請求方式,會在「CORS_ALLOW_METHODS」中查找,存在則經過,不存在則不容許跨域,或在「CORS_ALLOW_METHODS」中添加該請求方式
Access-Control-Request-Headers
該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段,會在「CORS_ALLOW_HEADERS」中查找,存在則經過,不存在則不容許跨域,或在「CORS_ALLOW_HEADERS中」添加該頭信息
另一種跨域的解決方案
JSOBP
只能發送GET請求,主要修改在前段部分,後端須要作約束脩改,發jsonp請求。優點在於支持老式瀏覽器,以及向不支持CORS的網站請求數據。
相關資料參考:
Django-cors-headers:https://github.com/ottoyiu/django-cors-headers/
瀏覽器同源策略及其規避方法:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
Django跨域請求:https://www.cnblogs.com/Joe1991/articles/8483770.html
跨域資源共享CORS 詳解: http://www.ruanyifeng.com/blog/2016/04/cors.html