我們?cè)谟肈jango框架編寫(xiě)后端服務(wù)器的時(shí)候,總會(huì)遇到如下問(wèn)題(No Access-Control-Allow-Origin header is present on the requested resource.)。

為什么會(huì)出現(xiàn)這種問(wèn)題呢?因?yàn)槲覀冊(cè)诤笈_(tái)訪問(wèn)的時(shí)候涉及到了在不同的域名下去獲取資源。一般都是由于CORS跨域驗(yàn)證機(jī)制設(shè)置不正確導(dǎo)致的。
先說(shuō)怎么去解決這種問(wèn)題:
在Django中我們可以在settings中去設(shè)置一些參數(shù)。
首先你需安裝Django中跨域的中間件:
首先我們需要安裝Django
然后在去安裝Django-cors-headers
方法:
pip install django-cors-headers
安裝好之后我們需要去settings中去注冊(cè)app。
INSTALLED_APPS = [
.....
'corsheaders'
.......
]
接下來(lái)我們需要在中間件中使用我們的cors跨域的中間件(在此需要注意一下,在Django的1.11版本中,中間件的變量名是MIDDLEWARE,在1.9版本中是MIDDLEWARE_CLASSES,所以說(shuō)要注意這兩種區(qū)別):
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
]
# 跨域請(qǐng)求是否攜帶cookies
CORS_ALLOW_CREDENTIALS = True
# 添加請(qǐng)求的白名單:
CORS_ORIGIN_WHITELIST = [
'http://127.0.0.1:8080',
'http://localhost:8000',
'http://www.meiduo.site:8000',
'http://api.meiduo.site.:8000'
]
什么是CORS呢?(Corss-Origin Resource Sharing 跨資源共享),也就是說(shuō)當(dāng)我們的請(qǐng)求與當(dāng)前的頁(yè)面的地址不同即為跨域。(包括協(xié)議,域名,端口等)。

可以看到的是我們?nèi)ピL問(wèn)一個(gè)頁(yè)面的時(shí)候,我們頁(yè)面的訪問(wèn)的地址是jd.com,但有的時(shí)候的資源卻放在另外一個(gè)資源路徑下,這寫(xiě)圖片的存放地址是360buy.com。最明顯的就是京東的案例。
下面我們?cè)敿?xì)的說(shuō)一下專(zhuān)業(yè)術(shù)語(yǔ):
Same Origin Policy:同源策略,尤其是JavaScript,是對(duì)于客戶端的腳本訪問(wèn)的一種安全標(biāo)準(zhǔn)。同源策略的精髓很簡(jiǎn)單:它認(rèn)為自任何站點(diǎn)裝載的信賴內(nèi)容是不安全的。當(dāng)被瀏覽器半信半疑的腳本運(yùn)行在本地的一個(gè)獨(dú)立的環(huán)境中時(shí),它們應(yīng)該只被允許訪問(wèn)來(lái)自同一站點(diǎn)的資源,而不是那些來(lái)自其它站點(diǎn)可能懷有惡意的資源。其實(shí)也是一種出于安全的考慮。
說(shuō)簡(jiǎn)單一點(diǎn),就是瀏覽器在訪問(wèn)一個(gè)服務(wù)器的資源的時(shí)候,這個(gè)網(wǎng)站內(nèi)不能去請(qǐng)求其他網(wǎng)站的資源,除非他們由相同的域名?;蛘呤窍嗤膮f(xié)議,以及相同的主機(jī)名以及端口。否則的話,是不被允許的,但是在大型的網(wǎng)站中他的資源肯定是放在不同的服務(wù)器上,有文件服務(wù)器,有視頻音頻服務(wù)器,有數(shù)據(jù)圖片服務(wù)器等。為了解決這種限制資源訪問(wèn)的問(wèn)題,就出現(xiàn)了CORS。
cors的運(yùn)行流程。
我們?cè)谠L問(wèn)一些網(wǎng)站主體的時(shí)候,例如網(wǎng)站是www.niubi.com.但是網(wǎng)站的圖片是從data.com返回的。其實(shí)在頁(yè)面中的實(shí)現(xiàn)過(guò)程是這樣的。
function getdata{
var request = new XMLHttpRequest();
request.open('GET','http://data.com',true)
request.onreadystatechange = handler;
request.send();
}
在運(yùn)行了這個(gè)網(wǎng)頁(yè)的文件加載到本地之后,就向數(shù)據(jù)服務(wù)器去發(fā)送請(qǐng)求,返回這些數(shù)據(jù)。
請(qǐng)求如下:
GET / HTTP/1.1
host: data.com
......
refer : http://niubi.com # 也就是說(shuō)數(shù)據(jù)從哪里來(lái)的。
Origin:http:niubi.com # 原來(lái)的請(qǐng)求的域名
我們?cè)谝粋€(gè)支持CORS協(xié)議的服務(wù)器會(huì)給我們?nèi)缦麓饛?fù)??梢钥吹降氖琼憫?yīng)頭中有一個(gè)值得注意的 Access-Control-Allow-Origin,這個(gè)響應(yīng)頭中記錄的是可以訪問(wèn)數(shù)據(jù)資源的域名。如果存在Access-Control-Allow-Origin,則就說(shuō)明瀏覽器知道這是一個(gè)可以跨域訪問(wèn)的,從而不會(huì)在根據(jù)Same Origin Policy來(lái)限制瀏覽器的跨域訪問(wèn)。其實(shí)整個(gè)流程看起來(lái)沒(méi)有什么區(qū)別。只是多了一個(gè)請(qǐng)求的過(guò)程,根據(jù)響應(yīng)來(lái)看是否允許瀏覽器來(lái)支持跨域訪問(wèn)。
響應(yīng)如下:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://ambergarden.com
Content-Type: application/xml
[Payload Here]