Ajax之跨域請求
一、引子
我現在開啟了兩個django專案,分別叫Demo1和Demo2,Demo1中有一個路徑‘http://127.0.0.1:8000/index/’,對應的檢視是index檢視返回一個index頁面,頁面中只有一個button按鈕,按鈕綁定了一個單擊事件,點選之後會發送一個ajax請求,請求的路徑為‘http://127.0.0.1:8001/ajax/’,Demo1的ip和埠號是:‘http://127.0.0.1:8000/’,Demo2的ip和埠號是:‘http://127.0.0.1:8001/’。前面一段描述就是在Demo1專案的一個頁面向Demo2專案傳送一個ajax請求,在Demo2有對應的路徑和檢視來處理請求,並返回值。我們執行一下。報錯如下:
這就是一個已攔截的跨域請求的錯誤,錯誤內容是CORS頭少“Access-Control-Allow-Origin”。這就是我們用ajax傳送一個跨域請求出現的錯誤,這就是今天我要處理的一個問題。
二、同源策略
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能就會受到影響,可以說web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
同源策略,它是由Netscape提出的一個著名的安全策略。現在所有支援JavaScript的瀏覽器都會用這個策略。所謂的同源,即指:域名、埠、協議同時相同。比如說你用ajax發請求時,會檢查你傳送的請求是否傳送路徑是否ajax所在的JavaScript屬於同源,即是兩者的ip、埠、協議相同。如果不是同源,瀏覽器就會報錯,提示拒絕訪問。
想要實現用ajax傳送跨域請求有兩種方式,一是jsonp,而是cors。
三、基於JSONP的ajax跨域請求
1,版本1
我們在用script引入js程式碼,有時用的是網上路徑,意思就是在我們的專案去請求其他專案的,如:
這種情況下是可以請求成功的,於是,我們可以運用這一功能,給button按鈕繫結事件,事件的功能是建立一個script標籤,然後新增到頁面上,這樣當我們點選button按鈕就會發送一個跨域請求,而且還是允許的。
Demo1專案index.html頁面上新增js程式碼:
function get_ele_script(url){ var ele_script=$('<script>'); ele_script.attr('src',url); ele_script.attr('id','ele_script'); $('body').append(ele_script); $('#ele_script').remove() } $('.cli').click(function () { get_ele_script('http://127.0.0.1:8001/ajax/') })
這樣就成功用點選事件傳送了一個跨域請求,在Demo2的檢視中,有返回值,但如果我不定義返回的值,HTML檔案就會報沒有定義的錯誤,而且檢視返回的值在前端頁面是以變數的形式顯示。
Demo2專案的檢視:
def ajax(request): dic={'name':'zhnag','age':46} dic_json=json.dumps(dic) return HttpResponse('f(%s)'%dic_json)
此時,我們就應該在HTML檔案中定義f()
function f(params) { console.log(params); console.log(typeof params); }
這樣,當我們點選button時,會往Demo2傳送一個請求,Demo2會返回帶引數的f(),由於已經定義了f()函式,所以當返回時會執行這個函式,這種方法就實現了傳送跨域請求,然後接受返回值,並對返回值進行處理。
2,版本2
其實版本1在Demo2專案中把返回的函式名寫死了,如果照版本1,所有來反問Demo2的瀏覽器都會得到一個叫f()的函式,我們在宣告的時候也只能寫成f()。其實我們可以這樣在請求的時候把我們定義的函式名一起發過去,讓他就給我返回我傳送過去的函式,這樣,我們定義函式名就可以隨意了。
Demo1專案的index.html頁面上就應這樣寫:
function f(params) { console.log(params); console.log(typeof params); } $('.cli').click(function () { get_ele_script('http://127.0.0.1:8001/ajax/?callbacks=f')
Demo2專案的檢視:
def ajax(request): a=request.GET.get('callbacks') dic={'name':'zhnag','age':46} dic_json=json.dumps(dic) return HttpResponse('%s(%s)'%(a,dic_json))
3,版本3
上面兩個版本就沒有基於ajax請求,這個版本就基於ajax傳送跨域請求。
Demo1專案下的index.html頁面上:
function f(params) { console.log(params); console.log(typeof params); } $('.cli').click(function () { $.ajax({ url:'http://127.0.0.1:8001/ajax/callbacks=f', type:'GET', dataType:'jsonp', }) })
Demo2專案的檢視:
def ajax(request): a=request.GET.get('callbacks') dic={'name':'zhnag','age':46} dic_json=json.dumps(dic) print(type(dic_json)) return HttpResponse('%s(%s)'%(a,dic_json))
4,版本4
這也是基於ajax傳送的跨域請求,只是比上一版本更簡單。
Demo1專案下的index.html:
function f(params) { console.log(params); console.log(typeof params); } $('.cli').click(function () { $.ajax({ url:'http://127.0.0.1:8001/ajax/', type:'GET', dataType:'jsonp', jsonp:'callbacks', jsonpCallback:'f' }) })
Demo2專案的檢視:
def ajax(request): a=request.GET.get('callbacks') dic={'name':'zhnag','age':46} dic_json=json.dumps(dic) print(type(dic_json)) return HttpResponse('%s(%s)'%(a,dic_json))
5,版本5(終極版本)
基於ajax的跨域請求,並把返回值給ajax的success。
Demo1專案下的index.html:
$('.cli').click(function () { $.ajax({ url:'http://127.0.0.1:8001/ajax/', type:'GET', dataType:'jsonp', jsonp:'callbacks', success:function (data) { console.log(data) } }) })
Demo2專案下的檢視:
def ajax(request): a=request.GET.get('callbacks') dic={'name':'zhnag','age':46} dic_json=json.dumps(dic) return HttpResponse('%s(%s)'%(a,dic_json))
這個版本就比較簡單,書寫方便
四、基於CORS的ajax跨域請求
最開始,我們講的報錯是:CORS頭少:‘Access-Control-Allow-Origin’,既然少一個,我們就加一個,就可以了,其實這種方式才是最常用。
Demo1專案下的index.html:
$('.cli').click(function () { $.ajax({ url:'http://127.0.0.1:8001/ajax/', type:'get', data:{'a':1}, success:function (res) { console.log(res) } }) })
Demo2專案下的檢視:
def ajax(request): dic = {'name': 'zhnag', 'age': 46} http=HttpResponse(json.dumps(dic)) http['Access-Control-Allow-Origin']='http://127.0.0.1:8000'#這相當於加了一個白名單,對於‘http://127.0.01:8000’的跨域請求就允許通行 return http