引子
使用Django在服務(wù)器端寫了一個API,返回一個JSON數(shù)據(jù)。使用Ajax調(diào)用該API:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <meta name= "viewport" content= "maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" /> <title>test</title> </head> <body> <button onclick= "showPersonInfo()" >點我獲取數(shù)據(jù)</button> </body> <script src= "http://libs.baidu.com/jquery/1.9.0/jquery.js" ></script> <script> function showPersonInfo(){ $.getJSON( 'http://xxx/account/getuserinfo/' , {username: "abc" }, function (json) { var html= '<br>' + '用戶名:' +json.username+ '<br>' + '姓:' +json.first_name+ '<br>' + '名:' +json.last_name+ '<br>' + '郵箱' +json.email; document.write(html); } ) } </script> </html> |
但是,Chrome瀏覽器提示錯誤:
1
|
No 'Access-Control-Allow-Origin' header is present on the requested resource. |
經(jīng)過一番Google發(fā)現(xiàn)這個問題是——CORS導(dǎo)致的。
什么是CORS?
CORS(跨域資源共享,Cross-Origin Resource Sharing)是一種跨域訪問的機(jī)制,可以讓Ajax實現(xiàn)跨域訪問。
其實,在服務(wù)器的response header中,加入“Access-Control-Allow-Origin: *”即可支持CORS,非常的簡單,apache/nginx等怎么配置,見參考文檔。
舉個例子:
- API部署在DomainA上;
- Ajax文件部署在DomainB上,Ajax文件會向API發(fā)送請求,返回數(shù)據(jù);
- 用戶通過DomainC訪問DomainB的Ajax文件,請求數(shù)據(jù)
以上過程就發(fā)生了跨域訪問。如果直接使用Ajax來請求就會失敗,就像Chrome提示的:
1
|
No 'Access-Control-Allow-Origin' header is present on the requested resource. |
如何解決Ajax跨域訪問問題?
解決跨域問題,有兩個方法:1.使用jsonp 2.使CORS生效
使用jsonp方法,需要讓服務(wù)器端放回jsonp格式的response,如Django可以加jsonp相關(guān)的decorator,如:https://coderwall.com/p/k8vb_a/returning-json-jsonp-from-a-django-view-with-a-little-decorator-help由于我不太喜歡這種方式,所以這里略過了,可看后面的參考資料。
使用CORS:這個用起來比較方便,現(xiàn)在大多數(shù)瀏覽器都支持了,且我web服務(wù)器完全開放給別人調(diào)用,所以比較推薦CORS。
1.使用JSONP
使用Ajax獲取json數(shù)據(jù)時,存在跨域的限制。不過,在Web頁面上調(diào)用js的script腳本文件時卻不受跨域的影響,JSONP就是利用這個來實現(xiàn)跨域的傳輸。因此,我們需要將Ajax調(diào)用中的dataType從JSON改為JSONP(相應(yīng)的API也需要支持JSONP)格式。
JSONP只能用于GET請求。
2.直接修改Django中的views.py文件
修改views.py中對應(yīng)API的實現(xiàn)函數(shù),允許其他域通過Ajax請求數(shù)據(jù):
1
2
3
4
5
6
7
|
def myview(_request): response = HttpResponse(json.dumps({ "key" : "value" , "key2" : "value" })) response[ "Access-Control-Allow-Origin" ] = "*" response[ "Access-Control-Allow-Methods" ] = "POST, GET, OPTIONS" response[ "Access-Control-Max-Age" ] = "1000" response[ "Access-Control-Allow-Headers" ] = "*" return response |
3.安裝django-cors-headers
這里還有一各發(fā)現(xiàn)!在Django中,有人開發(fā)了CORS-header的middleware,只在settings.py中做一些簡單的配置即可,見:https://github.com/ottoyiu/django-cors-headers/現(xiàn)在用起來服務(wù)器端完全開放,開啟CORS,沒有跨域煩惱,真爽!~
安裝django-cors-headers:
1
|
pip install django-cors-headers |
在settings.py中增加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
INSTALLED_APPS = ( ... 'corsheaders' , ... ) ... MIDDLEWARE_CLASSES = ( ... 'corsheaders.middleware.CorsMiddleware' , 'django.middleware.common.CommonMiddleware' , ... ) |
可以配置允許跨域訪問的白名單或者直接設(shè)置為允許所有的跨域訪問,具體的配置可以看看他們的github頁說明。