Django的跨域請求--JSONP的本質
通常我們在寫web端的代碼,可以通過url獲得想對應的響應數據如:
1.urls.py
urlpatterns = [
url(r'^get_data/', views.data),
]
2.views.py
def data(request):
return HttpResponse("機密數據")
而對於這個“機密數據”我們可以通過url直接可以獲取如下
也可以通過其他的終端獲取如下
那么現在有一個問題如果有個第三方的web端通過它的頁面想讓這段機密數據在自己的web頁面上進行顯示時如何實現:
第一步:
新創建一個Django的web服務:
1、urls.py
2.views.py
def index(request):
return render(request,"index.html")
3.html
4.啟動web(因為同時啟動兩個Django需將對應的端口修改)
現在一個web(機密數據),一個web(維基解密),現在的需求就是維基解密想將機密數據在其index的頁面進行顯示,這個如何完成???
這個方法有很多種:
方法1:通過后端請求:
-
views.py
def index(request): response = requests.get('http://127.0.0.1:8000/get_data/').text return render(request,"index.html",{'response':response})
-
index.html
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{% static 'jquery-3.2.1.js'%}"></script> </head> <body> <h1>維基解密</h1> <b>{{ response }}</b> </body> </html>
渲染效果
該方法通過后台相當於發送了兩次get請求才將數據取到
方法2:前端Ajax獲取
-
index.html
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{% static 'jquery-3.2.1.js' %}"></script> </head> <body> <h1>維基解密</h1> <b>{{ response }}</b> <script> $.ajax({ url:'http://127.0.0.1:8000/get_data/', type:'GET', success:function(arg){ alert(arg) } }) </script> </body> </html>
但是會遇到下面這個情況使我們無法獲取數據:
其實這個是我們的瀏覽器會攔截:
具體瀏覽器從什么時候進行攔截的我們可以驗證
所以這里可以知道其實機密數據的數據已經發送過來只是被瀏覽器給攔截,那對於這種情況我們應該如何繞過攔截而獲取數據??
如何繞過瀏覽器的同源策略
一、JSONP方式
從以往的前端HTML我們可以知道,其實在HTML的一些標簽中有些標簽是不受同源策略的影響如:
-
img標簽
-
script 標簽
-
iframe標簽
所以通過這個點我們可以將代碼做修改利用這些標簽的屬性來繞過瀏覽器的同源策略:
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
<script src="http://127.0.0.1:8000/get_data/"></script>
</head>
<body>
<h1>維基解密</h1>
</body>
</html>
這里我們利用script的src的屬性直接將機密數據的url放置,按理應該是可以將數據給我們返回的:
執行的結果如下:
上面顯示數據其實我們已經拿到了,但是沒有渲染在頁面上,報錯提醒是該端值未定義!!
這是因為我們使用的是script標簽將我們取到的機密數據只是一個單純的文本格式,而script是渲染js文檔的所有顯示顯示沒有定義的變量:
我們可以進行驗證如下:
1.現將機密數據作為一個func的函數參數渲染
2.維基解密的index.html的html
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
<script>
function func(arg){
console.log(arg);
}
</script>
<script src="http://127.0.0.1:8000/get_data/"></script>
</head>
<body>
<h1>維基解密</h1>
<b>{{ response }}</b>
</body>
</html>
這段代碼我們先定義了func,再用script引入機密數據
3.結果
這樣我們很好的繞開了瀏覽器的同源策略並取到數據
我們還可以進一步的優化代碼
views.py
index.html的html代碼
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
</head>
<body>
<h1>維基解密</h1>
<input type="button" onclick="jsonp('http://127.0.0.1:8000/get_data?callback=funcxxx')" value="發送JSONP請求">
<script>
function funcxxx(arg) {
alert(arg);
}
function jsonp(url){
var tag = document.createElement('script');
tag.src = url;
document.head.appendChild(tag);
document.head.removeChild(tag);
}
</script>
</body>
</html>
上述代碼就是jsonp的本質執行的過程
而在jQuery中提供了jsonp的方式:
index.html的html代碼
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
</head>
<body>
<h1>維基解密</h1>
<input type="button" onclick="jsonp()" value="發送JSONP請求">
<script>
function jsonp(){
$.ajax({
url:"http://127.0.0.1:8000/get_data?callback=funcxxx",
type:'GET',
dataType:'JSONP',
success:function(data){
console.log(data);
}
})
}
</script>
</body>
</html>
而這個的實現原理實質是和之前寫的源碼一樣
結論:
**優點:**1.通過jsonp的傳輸方式我們可以繞開瀏覽器同源策略。
2.頁面不用刷新而獲得數據
缺陷:
1.遠程數據的本地需要將數據封裝在函數中
2.本地需要定義被封裝的函數
3.JSONP只能發送GET請求
下面有個實例:
將JX衛視的節目單取到
index.html的html代碼
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
</head>
<body>
<h1>維基解密</h1>
<input type="button" onclick="jsonp()" value="發送JSONP請求">
<script>
function list(arg){
console.log(arg)
}
function jsonp(){
$.ajax({
url:"http://www.jxntv.cn/data/jmd-jxtv2.html",
type:'GET',
dataType:'JSONP',
jsonp:'callback',
jsonpCallback:'list'
})
}
//這里的 jsonp:'callback',jsonpCallback:'list相當於
url:"http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list",
</script>
</body>
</html>
結果如下: