天天看點

jsonp跨域原理_【網站技術解讀①】Javascript實作跨域請求

推薦一個讀者做的不錯的程式設計學習網站:

網站:潛安

域名:http://www.qianani.com

另外将會不定期推送近期網站用到的一些技術,講一些核心原理,今天為第一篇

問題由來:

最近一直在優化兩個Python學習網站,自己給自己提點需求,看看能不能實作,比如下方為http://www.python88.cn網站,在這個網站中,我做了一個功能,檢測使用者是否在該網站掃碼并輸入驗證碼,如果掃碼驗證過,則在後端記錄并傳回前端列印出來"right",如果沒有掃碼驗證,則傳回“error",傳回這樣标記的目的是為了通過這個标志是否做出右下角的彈窗,如果沒有驗證的使用者,則會彈出右下角的彈窗,當然在這個網站中這點已經很容易實作了

jsonp跨域原理_【網站技術解讀①】Javascript實作跨域請求

接下來需求就來了,下方是http://www.python66.cn第二個網站,因為我想通過http://python66.cn向http://python88.cn網站引流,點選彈窗能跳轉到http://88.cn網站,同樣,我也想通過使用者能否擷取在第一個網站掃碼(傳回的right或error)來判斷是否彈出下方的彈窗,這樣則牽涉到跨域請求

jsonp跨域原理_【網站技術解讀①】Javascript實作跨域請求
什麼是跨域請求:

舉個例子:假如一個域名為http://aaa.cn的網站,它發起一個資源路徑為http://aaa.cn/book/100.html的 Ajax 請求,那麼這個請求是同域的,因為資源路徑的協定、域名以及端口号與目前域一緻(例子中協定名預設為http,端口号預設為80)。但是,如果發起一個資源路徑為http://bbb.com/doc的 Ajax 請求,那麼這個請求就是跨域請求,因為域不一緻,與此同時由于安全問題,這種請求會受到同源政策限制。

ajax隻能請求同一個域下的資料或資源,有時候需要跨域請求資料,就需要用到jsonp技術(還有其他方式也可以跨域請求),jsonp可以跨域請求資料,它的原理主要是利用了<script><img>标簽具有src屬性可以跨域連結資源的特性。jsonp和ajax原理完全不一樣,不過jquery将它們封裝成同一個函數。

如何了解<script><img>标簽具有src屬性标簽可以跨域連結資源?

比如這是我在csdn的文章,裡面的圖檔引入的是我http://python88.cn的網站圖檔,就是典型的跨域,包括我們<script>标簽,有時候也會通過src引入一些網絡上的架構,也是這個道理,jsonp就是通過這樣的原理來實作的跨域

jsonp跨域原理_【網站技術解讀①】Javascript實作跨域請求

原理基于上面原理,但是一般我們在用的時候,通過jQuery封裝好的方法來進行使用,下面開始上代碼

1、首先我在後端視圖中定義一個book_ip_sign2函數,并同步配置url

說明,jsonp跨域請求隻能接受get請求,不支援post請求

def book_ip_sign2(request):
   user_ip = request.META['REMOTE_ADDR']
   print("***********")
   print(user_ip)
   engine = get_local_engine()
   ip_df = pd.read_sql("find_ip_num", engine)
   ip_list = list(ip_df["ip"])
   if user_ip not in ip_list:
       print("新的使用者IP")
       func = request.GET.get('callback', None)
       context = {"user_ip": user_ip, "book_click_sign": "error","find_ip_num":num}
       return HttpResponse("%s(%s)"%(func,context))
   else:
       current_user = FindIpNum.objects.filter(ip=user_ip)
       current_num = current_user[0].num
       if current_num < 3:
           func = request.GET.get('callback', None)
           context = {"user_ip": user_ip, "book_click_sign": "error","find_ip_num":current_num}
           return HttpResponse("%s(%s)"%(func,context))
       elif current_num >= 3:
           func = request.GET.get('callback', None)
           context = {"user_ip": user_ip, "book_click_sign": "right", "find_ip_num":current_num}
           return HttpResponse("%s(%s)"%(func,context))
           

對于上面代碼,看着很多,不過你可以忽略那些業務邏輯,隻需要看傳回的資料即可,我這裡主要想傳回三個資料(book_click_sign , current_num, user_ip),直接将這幾個構造成context通過JsonResponse傳回是不行的,前端會報錯,後來找了點資料,發現要跟回調函數拼接,也就是下面的,func是回調函數名,通過拼接用HttpResponse進行傳回

func = request.GET.get('callback', None)
context = {"user_ip": user_ip, "book_click_sign": "right", "find_ip_num":current_num}
return HttpResponse("%s(%s)"%(func,context))
           

前端檢視該傳回結果是這樣的,括号中就是我們傳回前端的資料,也是回調函數的參數(回調函數名+參數)

jQuery17104493579000703556_1550910515349('error_0_139.227.3.199')
           
2、前端jsonp請求

前端引入jQuery,通過$.ajax進行請求,注意這裡的jsonp和ajax原理完全不一樣,這裡$.ajax .done .fail此類隻是jQuery官方将兩種請求封裝成了看起來類似的方法

核心請求頭就是url,type,dataType這些,如果請求成功,則通過.done寫js邏輯,如果請求失敗則通過.fail寫js邏輯

傳回的data: 後端回調函數括号中的參數即傳回前端的最終data

error_0_139.227.3.199
           
$.ajax({
   url:'http://www.python88.cn/book_ip_sign2/',
   type:'get',
    dataType:'jsonp',
})
.done(function(data){
    book_click_sign = data.book_click_sign;
    find_ip_num = data.find_ip_num;
    user_ip = data.user_ip;
    console.log(user_ip)
    console.log(find_ip_num)
    console.log(book_click_sign)
    if(book_click_sign=="error"){
       $("#hzw_showmsg").delay(5000).slideDown(1000);
    }else{
       console.log("放過一次")
    }         
})
           

大家如果想測試,可以去http://www.python66.cn前端欄目下載下傳源碼,下載下傳後是一個html檔案,通過控制台就能看到跨域請求傳回的結果