一般情況下我們的請(qǐng)求只能給自己的網(wǎng)站發(fā)送請(qǐng)求,如果給別的網(wǎng)站發(fā)送請(qǐng)求時(shí),瀏覽器會(huì)進(jìn)行同源限制,跨域請(qǐng)求就是我們的網(wǎng)站如果要獲取其他網(wǎng)站的數(shù)據(jù)的話,可以通過(guò)一下方式實(shí)現(xiàn)
例如:要獲得以下數(shù)據(jù)
def get_data(request):
return HttpResponse('數(shù)據(jù)')
使用代碼完成跨域請(qǐng)求
request發(fā)送請(qǐng)求的時(shí)候跨域無(wú)限制
def test1(request):
response = requests.get('http://127.0.0.1:8000/get_data/')
return render(request, 'test1.html', {'response': response})
在前端顯示
{{ response.text }}
jsonp實(shí)現(xiàn)跨域請(qǐng)求
別人數(shù)據(jù)
def get_data(request):
func_name = request.GET.get('callback')
return HttpResponse('%s("數(shù)據(jù)")' % func_name)
使用jsonp實(shí)現(xiàn)跨域請(qǐng)求
<script>
function func(arg){
console.log(arg)
}
$.ajax({
url: "http://127.0.0.1:8000/get_data/",
type: 'GET',
dataType: 'JSONP',
jsonp: 'callback',
jsonpCallback: 'list'
});
</script>
注意:
首先,要讓別人對(duì)數(shù)據(jù)進(jìn)行處理
其次,為了讓獲得的數(shù)據(jù)易讀,需要將數(shù)據(jù)進(jìn)行l(wèi)ist
其原理是使用帶有src的標(biāo)簽不會(huì)收到同源限制,而且要求自己定義一個(gè)數(shù)據(jù),使用標(biāo)簽引入,而且要求別人也要在數(shù)據(jù)外面包一層數(shù)據(jù),如下
自己獲得
<script>
function func(arg) {
console.log(arg);
}
</script>
<script src="http://127.0.0.1:8000/get_data/?callback=func"></script>
我們也可以手動(dòng)創(chuàng)建標(biāo)簽
<script>
function func(arg) {
alert(arg);
document.head.removeChild(tag);
}
function jsonp(url){
tag = document.createElement('script');
tag.src = url;
document.head.appendChild(tag);
}
jsonp('http://127.0.0.1:8000/get_data/?callback=func')
</script>
應(yīng)用場(chǎng)景:
調(diào)用者需要和數(shù)據(jù)提供者協(xié)商,首先需要數(shù)據(jù)提供者提供一個(gè)API,然后互相商討使用哪一種方式提取數(shù)據(jù),如果使用jsonp格式提取數(shù)據(jù)的話需要數(shù)據(jù)提供者對(duì)數(shù)據(jù)進(jìn)行一定的處理(獲得callback,然后使用callback包裹你的數(shù)據(jù)),如果不想讓數(shù)據(jù)提供者麻煩的話,就只能用自帶的request模塊來(lái)實(shí)現(xiàn)
core方法
首先要明白,jsonp進(jìn)行跨域請(qǐng)求的方法是繞過(guò)同源策略,使用帶有src的標(biāo)簽進(jìn)行請(qǐng)求
其次,瀏覽器為什么會(huì)進(jìn)行同源策略,其實(shí)在請(qǐng)求可以順利的到達(dá)對(duì)方的URL,也同樣能取到數(shù)據(jù),但是在返回的時(shí)候少了Access-Control-Allow-Origin 響應(yīng)頭,因此,我們的做法就是將頭加進(jìn)去
別人數(shù)據(jù)
def get_data(request):
response = HttpResponse('數(shù)據(jù)')
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8899' # 如果為*的話對(duì)所有請(qǐng)求有效
return response
這樣讓別人的數(shù)據(jù)進(jìn)行處理之后我們自己就按照一般情況請(qǐng)求就可以了
$.ajax({
url: 'http://127.0.0.1:8000/get_data/',
type: 'GET',
success: function (data) {
console.log(data);
}
})
如果我們給別人提供數(shù)據(jù)的話,如果允許所有的人都可以請(qǐng)求的話,使用中間件比較好
注意:
我門正規(guī)的請(qǐng)求稱為簡(jiǎn)單請(qǐng)求,但是,有時(shí)候發(fā)請(qǐng)求的時(shí)候會(huì)發(fā)送復(fù)雜請(qǐng)求,請(qǐng)求方式改變或者請(qǐng)求頭的改變可以變?yōu)閺?fù)雜請(qǐng)求,
如果發(fā)送的是復(fù)雜請(qǐng)求的話,首先會(huì)發(fā)送一個(gè)option,然后發(fā)送數(shù)據(jù),復(fù)雜請(qǐng)求接受到的request.method是option
因此數(shù)據(jù)提供者應(yīng)該在接受請(qǐng)求的時(shí)候進(jìn)行一個(gè)判斷,如果request.method的話,將請(qǐng)求方式和請(qǐng)求頭進(jìn)行修改,然后再發(fā)送數(shù)據(jù)
由于復(fù)雜請(qǐng)求發(fā)送兩次,嚴(yán)重影響效率,因此我們應(yīng)該盡量避免發(fā)送復(fù)雜請(qǐng)求
兼容復(fù)雜請(qǐng)求代碼如下
def get_data(request):
if request.method == "OPTIONS":
# 預(yù)檢
response = HttpResponse()
response['Access-Control-Allow-Origin'] = "*"
# response['Access-Control-Allow-Methods'] = "PUT"
response['Access-Control-Allow-Headers'] = "xxx" # 注意在前端也是要一樣的
return response
elif request.method == "GET":
response = HttpResponse("機(jī)密數(shù)據(jù)")
response['Access-Control-Allow-Origin'] = "*"
return response
跨站獲取相應(yīng)頭
默認(rèn)獲取到的所有響應(yīng)頭只有基本信息,如果想要獲取自定義的響應(yīng)頭,則需要再服務(wù)器端設(shè)置Access-Control-Expose-Headers。
跨站傳cookie
在跨域請(qǐng)求中,默認(rèn)情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無(wú)論在預(yù)檢請(qǐng)求中或是在實(shí)際請(qǐng)求都是不會(huì)被發(fā)送。
如果想要發(fā)送:
- 瀏覽器端:XMLHttpRequest的withCredentials為true
- 服務(wù)器端:Access-Control-Allow-Credentials為true
- 注意:服務(wù)器端響應(yīng)的 Access-Control-Allow-Origin 不能是通配符