Python開發之AJAX


一、概述

對於WEB應用程序:用戶瀏覽器發送請求,服務器接收並處理請求,然后返回結果,往往返回就是字符串(HTML),瀏覽器將字符串(HTML)渲染並顯示瀏覽器上。

1、傳統的Web應用:一個簡單操作需要重新加載全局數據。

2、Ajax

AJAX,Asynchronous JavaScript and XML (異步的JavaScript和XML),一種創建交互式網頁應用的網頁開發技術方案。
 
異步的JavaScript:
    使用 【JavaScript語言】 以及 相關【瀏覽器提供類庫】 的功能向服務端發送請求,當服務端處理完請求之后,【自動執行某個JavaScript的回調函數】。
PS:以上請求和響應的整個過程是【偷偷】進行的,頁面上無任何感知。
XML
    XML是一種標記語言,是Ajax在和后台交互時傳輸數據的格式之一
PS:
XML 一般用於編寫配置文件,語法方便描述配置文件內的信息,舉例如下:
<start>  
    <username>xiaowang</username>
    <age>18</age>
       .....
</start>
 
利用AJAX可以做:
1、注冊時,輸入用戶名自動檢測用戶是否已經存在。
2、登陸時,提示用戶名密碼錯誤
3、刪除數據行時,將行ID發送到后台,后台在數據庫中刪除,數據庫刪除成功后,在頁面DOM中將數據行也刪除。(博客園)

3、Ajax分類及定義

Ajax操作共分為三類:原生Ajax,jQuery Ajax,和偽Ajax 三種方式。這三種方法都能偷偷向后台發送請求。目前熟知的僅是 jquery ajax。

1. 原生ajax:是ajax本質,通過頁面的XMLHttpRequest對象來調用。send 發送數據,往請求體里放數據。
2. jquery與ajax的關系 內部基於"原生ajax" 是對原生ajax的封裝,使用起來簡單。
  jquery 相當於是個模塊,他調用了很多內置方法,把發送ajax請求的方法,封裝在了其內部,我們使用的時候直接調用ajax這個函數即可。
3. 偽ajax,不用XMLHttpRequest對象,使用瀏覽器里的標簽和標簽的特性偽造出來的。

二、原生Ajax

  Ajax主要就是使用 【XmlHttpRequest】對象來完成請求的操作,該對象在主流瀏覽器中均存在(除早期的IE),Ajax首次出現IE5.5中存在(ActiveX控件)。

XmlHttpRequest對象介紹

a. void open(String method,String url,Boolen async)
   用於創建請求
     
   參數:
       method: 請求方式(字符串類型),如:POST、GET、DELETE...
       url:    要請求的地址(字符串類型)
       async:  是否異步(布爾類型)
  
b. void send(String body)
    用於發送請求
  
    參數:
        body: 要發送的數據(字符串類型)
  
c. void setRequestHeader(String header,String value)
    用於設置請求頭
  
    參數:
        header: 請求頭的key(字符串類型)
        vlaue:  請求頭的value(字符串類型)
  
d. String getAllResponseHeaders()
    獲取所有響應頭
  
    返回值:
        響應頭數據(字符串類型)
  
e. String getResponseHeader(String header)
    獲取響應頭中指定header的值
  
    參數:
        header: 響應頭的key(字符串類型)
  
    返回值:
        響應頭中指定的header對應的值
  
f. void abort()
  
    終止請求

2、XmlHttpRequest對象的主要屬性:

a. Number readyState
   狀態值(整數)
  
   詳細:
      0-未初始化,尚未調用open()方法;
      1-啟動,調用了open()方法,未調用send()方法;
      2-發送,已經調用了send()方法,未接收到響應;
      3-接收,已經接收到部分響應數據;
      4-完成,已經接收到全部響應數據;
  
b. Function onreadystatechange
   當readyState的值改變時自動觸發執行其對應的函數(回調函數)
  
c. String responseText
   服務器返回的數據(字符串類型)
  
d. XmlDocument responseXML
   服務器返回的數據(Xml對象)
  
e. Number states
   狀態碼(整數),如:200、404...
  
f. String statesText
   狀態文本(字符串),如:OK、NotFound...
 function func1() {
        var xmlhttp = createHMLHttpRequeset();
        xmlhttp.open("POST", "/ajax_recevie/", true) //請求的監控的地址
        xmlhttp.send("name-NBA")
        xmlhttp.onreadystatechange = function () {
            if (xmlhttp.readyState == 4 /*&& xmlhttp.status==200*/) {
                var data = xmlhttp.responseText
                alert(data)
            };
        }
    }
     function  createHMLHttpRequeset() {
       //創建一個XMLHttpRequest,try防止瀏覽器不一致造成創建不成功
      /* var xmlHttp;
       try {
           xmlHttp=new  XMLHttpRequest();
       }catch (e){
           try{
               xmlHttp =new  ActiveXObject("Msxml2.XMLHTTP");
           }catch (e){
               try {
                   xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
               }catch (e){}
           }
       }
       return xmlHttp;*/
      var xmlHttp;
      xmlHttp=new  XMLHttpRequest();
      return xmlHttp
     }
創建一個XmlHttpRequest請求

3、跨瀏覽器支持

XmlHttpRequest
  IE7+, Firefox, Chrome, Opera, etc.

ActiveXObject("Microsoft.XMLHTTP")

  IE6, IE5

三、jQuery Ajax

jQuery其實就是一個JavaScript的類庫,其將復雜的功能做了上層封裝,使得開發者可以在其基礎上寫更少的代碼實現更多的功能。

    jQuery 不是生產者,而是原生ajax的搬運工。

    jQuery Ajax本質 XMLHttpRequest 或 ActiveXObject 

jQuery.get(...)
                所有參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數。
                 success: 載入成功時回調函數。
                dataType: 返回內容格式,xml, json,  script, text, html


            jQuery.post(...)
                所有參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數
                 success: 載入成功時回調函數
                dataType: 返回內容格式,xml, json,  script, text, html


            jQuery.getJSON(...)
                所有參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數。
                 success: 載入成功時回調函數。


            jQuery.getScript(...)
                所有參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數。
                 success: 載入成功時回調函數。


            jQuery.ajax(...)

                部分參數:

                        url:請求地址
                       type:請求方式,GET、POST(1.9.0之后用method)
                    headers:請求頭
                       data:要發送的數據
                contentType:即將發送信息至服務器的內容編碼類型(默認: "application/x-www-form-urlencoded; charset=UTF-8")
                      async:是否異步
                    timeout:設置請求超時時間(毫秒)
                    traditional: true,// 如果提交的數據的值有列表,則需要添加此屬性,讓數據不做轉換。
                 beforeSend:發送請求前執行的函數(全局)
                   complete:完成之后執行的回調函數(全局)
                    success:成功之后執行的回調函數(全局)
                      error:失敗之后執行的回調函數(全局)
                

                    accepts:通過請求頭發送給服務器,告訴服務器當前客戶端課接受的數據類型
                   dataType:將服務器端返回的數據轉換成指定類型
                                   "xml": 將服務器端返回的內容轉換成xml格式
                                  "text": 將服務器端返回的內容轉換成普通文本格式
                                  "html": 將服務器端返回的內容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript標簽,則會嘗試去執行。
                                "script": 嘗試將返回值當作JavaScript去執行,然后再將服務器端返回的內容轉換成普通文本格式
                                  "json": 將服務器端返回的內容轉換成相應的JavaScript對象
                                 "jsonp": JSONP 格式
                                          使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函數名,以執行回調函數

                                  如果不指定,jQuery 將自動根據HTTP包MIME信息返回相應類型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string

                 converters: 轉換器,將服務器端的內容根據指定的dataType轉換類型,並傳值給success回調函數
                         $.ajax({
                              accepts: {
                                mycustomtype: 'application/x-some-custom-type'
                              },
                              
                              // Expect a `mycustomtype` back from server
                              dataType: 'mycustomtype'

                              // Instructions for how to deserialize a `mycustomtype`
                              converters: {
                                'text mycustomtype': function(result) {
                                  // Do Stuff
                                  return newresult;
                                }
                              },
                            });
jQuery Ajax方法列表

原生Ajax及jQuery Ajax使用示例:

- index.html頁面設置兩種方法,方便於比較

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/js/jquery-3.2.1.js"></script>
</head>
<body>
<input type="text" id ="i1">
+
<input type="text" id="i2">
=
<input type="text" id="es">
<p>
    <input type="button" id="btn1" value="提交" onclick="add1();">
    <input type="button" id="btn2" value="原生提交" onclick="add2();">
</p>
<script>
    function add1() {
        $.ajax({
            url:"/add1/",
            type:"POST",
            data:{"i1":$("#i1"),"i2":$("#i2")},
            success:function (arg) {
                $("#es").val(arg);
            }
        })
    }
    function add2() {
        var xhr = new XMLHttpRequest();
{#        只要狀態發生變化,就會立馬被執行#}
        xhr.onreadystatechange = function () {
            if (xhr.readyState==4){
                alert(xhr.responseText);
            } {# 回調函數,接收到從服務端返回的數據進行處理 #}
        };
{#        GET方式提交,數據放在url中#}
{#        xhr.open("GET","/add2/?i1=10&i2=18");#}
{#        xhr.send();#}
{#        POST方式提交#}
        xhr.open("POST","/add2/");  {# 打開連接 #}
{#        注意POST請求的時候,要設置請求頭信息,否則后台POST格式拿不到數據#}
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        xhr.send("i1=12&i2=19");  {# 發送數據 #}
    }
</script>
</body>
</html>
Vindex.html頁面

-views.py 視圖函數中的操作

from django.shortcuts import render,HttpResponse
import os
# Create your views here.

def index(request):
    return render(request,"index.html")

def add1(request):
    a1 = int(request.POST.get("i1"))
    a2 = int(request.POST.get("i2"))
    return HttpResponse(str(a1+a2))

def add2(request):
    if request.method == "GET":
        i1 = int(request.GET.get("i1"))
        i2 = int(request.GET.get("i2"))
        print("add2……")
        return HttpResponse(i1+i2)
    else:
        print(request.POST)
        i1 = int(request.POST.get("i1"))
        i2 = int(request.POST.get("i2"))
        print(request.body)
        print("add2……POST")
        return HttpResponse(i1+i2)
Views.py后台處理方式

四、偽 Ajax

  由於HTML標簽的iframe標簽具有局部加載內容的特性,所以可以使用其來偽造Ajax請求。

1、iframe 標簽:

標簽特性:在當前頁面不刷新的情況下,在本標簽的框內,完全加載其他頁面。

原理:src指定一個url地址,在當前頁面不刷新的情況下,直接把對應的整個網頁中所有的代碼加載到iframe標簽中。

- 示例:

  在頁面直接查看其他網頁,同時自己手動輸入網址,也可以查看對應頁面。

- autohome.html頁面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
<input type="text" id="txt1">
<input type="button" value="查看" onclick="changeScr();">
</div>
<iframe id="ifr" src="http://www.autohome.com.cn"></iframe>
<script>
    function changeScr() {
        var inp = document.getElementById("txt1").value;
        document.getElementById("ifr").src = inp
    }
</script>
</body>
</html>
頁面顯示

- views.py后台處理方式:

后台處理方式

注意點:

  1、iframe標簽內是整個頁面全拿到,沒錯就是所有的標簽和內容!相當於把另一個頁面copy到它標簽下。iframe可以實現在自己的標簽內部刷新,整個頁面不刷新而是局部刷新。具有不刷新就能打開頁面的效果。
  2、iframe標簽,具有不刷新頁面能發送http請求,打開相對應頁面的功能,當前頁面重新加載也不會發生改變。

基於這種方式,我們就想到利用iframe標簽的特性和form表單標簽具有提交數據的功能結合,偽造往后台提交數據的方法:

  iframe標簽與form標簽結合,把form表單內所有的數據交給iframe標簽,由iframe標簽提交給后台服務端。form表單中一條屬性target與iframe標簽的name建立聯系(target屬性值與name值一致),從而實現頁面不刷新,偷偷往后台發送數據的目的。

基於iframe標簽和Form表單實現偽ajax操作

注意點:頁面嵌套頁面需要通過特定的方法去尋找。得進入文本里邊去拿對應的文本內容。

代碼示例:

- 網頁代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form id="f1" method="POST" action="/fake_ajax/" target="ifr">
    <iframe id="ifr" name="ifr" frameborder="1"></iframe>
    <input type="text" name="user">
    <a onclick="submitForm();">提交</a>
</form>
<script>
    function submitForm() {
        document.getElementById("ifr").onload = loadIframe;
        document.getElementById("f1").submit();
    }
    function loadIframe() {
{#        alert(123);#}
        var content = document.getElementById("ifr").contentWindow.document.body.innerText;
        console.log(content);
    }
</script>
</body>
</html>
偽ajax方式提交之頁面

- views.py 后台處理

def fake_ajax(request):
    if request.method=="GET":
        return render(request,"fake_ajax.html")
    else:
        print(request.POST)
        print(request.POST.get("user"))
        return HttpResponse(request.POST.get("user"))
后台處理

關於解決頁面加載,函數未定義的問題:
  html標簽中設置一個提交按鈕,這個按鈕綁定一個點擊事件,這個事件在JS代碼中對應一個函數,該函數內部存在一個加載完成之后的綁定加載方法,這個方法再對應另一個函數。這樣就能解決頁面加載函數未定義的問題。
js代碼中,通過找到form標簽也可以完成提交的操作     DOM對象.submit()

基於ajax上傳文件(POST)方式提交,並在當前頁面預覽

1、原生ajax
  現在的主流瀏覽器都有一個FormData方法,基於formData對象,這個對象可以傳文件也可以傳字符串。
  獲取文件對象:通過input 便簽 type=files 的文件標簽對象.files[0]
  先在本地上傳完文件,再把該文件保存的地址返回給瀏覽器,頁面動態創建一個img標簽,src ="服務端返回的文件路徑"(注意文件路徑的格式<'/'開頭>需要拼接!!)。 用於文件的預覽(主要是圖片)。
2、jquery ajax
  注意也是構造內容對象,和傳值 data = FormData對象。
  傳輸文件注意,需要添加兩條屬性,告訴jquery不再做數據的處理。
    contentType:false,
    processData:false,

弊端:原生ajax和jQuery Ajax兩種方式,依賴FormData這個對象這就直接導致兼容性較差,主要是出來的時間太晚。

3、偽ajax
  相比上邊兩種操作,由於偽Ajax是由兩個標簽來完成數據提交操作的,而不是用插件,所以幾乎所有的瀏覽器都支持。上傳文件首選。

  使用form表單上傳文件,注意添加enctype屬性。
  注意從iframe標簽中拿數據的方式,及重新加載的方式。

文件提交示例:

- 上傳頁面及script操作:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/js/jquery-3.2.1.js"></script>
</head>
<body>
    <h1>原生Ajax上傳文件</h1>
    <input type="file" id="i1">
    <a onclick="upload1()">上傳</a>
    <div id="container1"></div>  {# 用於預覽圖片 #}

    <h1>jQuery Ajax上傳文件</h1>
    <input type="file" id="i2">
    <a onclick="upload2()">上傳</a>
    <div id="container2"></div>  {# 用於預覽圖片 #}

    <h1>偽Ajax上傳文件</h1>
    <form id="f1" method="POST" action="/upload/" target="ifr" enctype="multipart/form-data">
        <iframe id="ifr" name="ifr" style=""></iframe>
        <input type="file" name="files"/>
        <a onclick="upload3();">上傳</a>
    </form>
    <div id="c3"></div>

    <script>
        function upload1() {
            var formData = new FormData();{# 通過FormData對象獲取文件或字符串信息 #}
            formData.append("k1","v1");
            formData.append("files",document.getElementById("i1").files[0]);
            console.log(document.getElementById("i1"));
            console.log(document.getElementById("i1").files);
            console.log(document.getElementById("i1").files[0]);
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4){
                    var file_path = xhr.responseText;
                    var tag = document.createElement("img");
                    tag.src = "/"+file_path;
                    document.getElementById("container1").appendChild(tag);
                }
            };
            xhr.open("POST","/upload/");
            xhr.send(formData);
        }
        function upload2() {
            var formData = new FormData();
            formData.append("k1","v1");
            formData.append("files",$("#i2")[0].files[0]);
            $.ajax({
                url: "/upload/",
                type:"POST",
                data:formData,
                contentType:false,
                processData:false,
                success:function (arg) {
                    var tag = document.createElement("img");
                    tag.src="/"+arg;
                    $("#container2").append(tag);
                }
            })
        }
        function upload3() {
            document.getElementById("ifr").onload=loadIframes;
            document.getElementById("f1").submit();
        }
        function loadIframes() {
            var content = document.getElementById("ifr").contentWindow.document.body.innerText;{#在iframe標簽中獲取返回的數據#}
            var tags = document.createElement("img");
            tags.src = "/" + content;
            document.getElementById("c3").appendChild(tags);
        }
    </script>
</body>
</html>
upload.html

- 后台對請求處理操作:

def upload(request):
    if request.method =="GET":
        return render(request,"upload.html")
    else:
        print(request.POST,request.FILES)
        file_obj = request.FILES.get("files")
        file_path = os.path.join("static",file_obj.name)
        with open(file_path,"wb") as f:
            for chunk in file_obj.chunks():
                f.write(chunk)
        return HttpResponse(file_path)
Views.py 后台操作

關於上傳文件按鈕偽裝:

  任何一個頁面原生的按鈕都是丑陋了,為了好看都需要做一層偽裝。在一個框內寫上兩個標簽,一個input標簽,另一個自定義,然后設置優先級,把input的優先級調低並且透明度為0。顯示出好看的標簽。

以上三種提交數據總結:

記住一句話:根據使用情況而定使用哪種方式提交數據。

1、若是實現上傳文件的功能,那首選 偽ajax,原因及就一點:兼容性強!

2、若是實現傳輸普通文本數據的功能,需要在兩個層面上考慮,一個是代碼的書寫難度,一個是性能;當然推薦使用jquery,因為簡單,但是需要導入一個300k左右的功能包;若是大公司,對性能上或是訪問量大的網站寫這種操作的話,就要首先考慮用原生ajax或是偽ajax,這兩種方法都是用幾行代碼去實現功能,不需要事先導入先導入一個模塊。

五、跨域Ajax

由於瀏覽器存在同源策略機制,同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。

特別的:由於同源策略是瀏覽器的限制,所以請求的發送和響應是可以進行,只不過瀏覽器不接受罷了。

瀏覽器同源策略並不是對所有的請求均制約:

  • 制約: XmlHttpRequest,
  • 不叼: img、iframe、script等具有src屬性的標簽

跨域,跨域名訪問,如:http://www.c1.com 域名向 http://www.c2.com域名發送請求。

JSONP實現跨域請求

  JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script標簽的src屬性(瀏覽器允許script標簽跨域)

JSONP    ------>注意一點:發送的是GET請求
    是一種技巧或是說技術,
    Ajax存在一個問題:訪問自己域名URL的請求是沒有任何問題的,但是訪問其他域名URL的時候,瀏覽器會做出相應的操作,請求就會被阻止。
產生原因:
    瀏覽器在當前頁面給第三方發送請求,數據也從服務器發會給瀏覽器,但是由於瀏覽器的同源策略,數據被瀏覽器禁止了,返回值就接收不到。
    由於這種原因,瀏覽器判定只能給當前的url發送請求,不能跨域。
    瀏覽器:同源策略
        - 禁止:Ajax跨域發送請求時,再回來時瀏覽器拒絕接收。
        - 允許:img,script標簽沒禁止  瀏覽器不會阻止src=""的加載。
     
處理方法:繞過瀏覽器的同源策略(鑽空子),既然禁止ajax跨域,但是允許帶有src屬性標簽進行跨域。
所以就不再用ajax去發送請求而是創建一個有這種屬性的標簽,然后把跨域請求的url寫到src屬性下,然后把這個帶有數據的標簽加到當前頁面上。
例如利用script便簽,然后請求返回的內容就會交給script進行解析。
 
利用src發送請求,就會把訪問的頁面內容完全下載下來,保存在內存當中。若是有對應的加載策略,頁面一刷新就能把型對應的數據在頁面上顯示出來。
     
    JSONP:鑽空子
        # http://www.baidu.com?p=1&name=xx
        0. function list(arg){
            console.log(arg);
          }
         
        1. 發送:把url地址放在標簽中
            把數據拼接成,script放在html
            <script src='http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403'></script>
            返回的是list({......})函數,當前頁面也得有一個相對應的調用函數,數據一返回就能執行這個調用的函數,把數據加載顯示出來。
        要求:遠程返回值必須是一個有參數的函數,在當前本地執行這個函數就能獲取到數據,所以我們都需要遵守這個規則。
         
        利用js 可以被瀏覽器加載的特性。
        當作js代碼放到瀏覽器所屬客戶端的內存中   
跨域請求,獲取其他網站的數據方法:
    第一種:瀏覽器向自己服務端發送請求,獲取到數據之后,再向其他網站的服務端發送請求,接收該服務端的返回的數據。這種方式需要考慮同源策略的問題。
    第二種:瀏覽器向自己的服務端發送請求,然后服務端再向要其他的服務端發送請求,獲取到數據,再把數據傳遞給瀏覽器。這種方式就不用考慮同源策略,也不會用到JSONP跨域操作了。
    注意:服務端不是瀏覽器,訪問任意網站發送請求,都會拿到返回的數據。
 
開發需求:向其他網站發Http請求  
    - 瀏覽器直接發送請求【考慮同源】
    - 瀏覽器->服務端->發送請求     
API:別人給提供的路徑或是方法,通過這個方法就能獲取到對應的數據。
 
瀏覽器直接發送請求【考慮同源】
注意:同源策略是瀏覽器做的策略,只要瀏覽器發送請求,服務端就會把數據返回給客戶端存放於內存中,能不能渲染還是瀏覽器說了算。  
    要求:客戶端和服務端協議必須達成一致,才可以實現跨域請求的操作!
        1. 客戶端
            - URL?callback=xxxx   服務端以GET形式發送請求,把函數名放在url中
            - function xxxx(arg){}  定義一個針對這個請求的自執行函數,用於加載后台返回的數據。
                 
        2. 服務端
            - 獲取 funcname = request.GET.get(callback) 獲取GET請求 url 中自定義的函數名
            - 返回: funcname(....)   以一個函數帶數據的形式返回給瀏覽器
     
    Jquery內部已經封裝了JSONP的方法,所以需要跨域的話,jquery內部也能實現操作,直接就使用jquery的對應方法即可。
    JSONP編寫模版:
        后台發送返回的數據,做成一個可操作的對象返回。瀏覽器前端接收到數據,然后利用js加載顯示獲取數據。
 
    注意:
        變量名要在瀏覽器中自己定義或命名,后台不用管直接對數據拼接操作就行,然后返回給瀏覽器。
        瀏覽器要自定義一個函數執行這個操作,只要后台把數據返回,就自動執行對應的函數,把數據顯示。
     
    使用:分為兩種方式:
        1. 自己動態創建script標簽,src添加url地址,定制加載函數。
            function getUsers(){
                 var tag = document.createElement('script');
                tag.src = "http://www.s4.com:8001/users/?funcname=bbb?sdd";
                document.head.appendChild(tag);
             }
        2. 直接利用jQuery ajax請求實現跨域操作,也需要自定義加載函數。
            $.ajax({
                url: 'http://www.s4.com:8001/users/',  跨域要訪問的地址
                type: 'GET',                           請求方式,必須是GET   換成了其他方式也會以GET方式請求。
                dataType: 'JSONP',                     指定參數,規定那種方法操作發送數據
                jsonp: 'funcname',                     GET請求名
                jsonpCallback: 'bbb'                   GET請求發送給后端的值
            })
    jquery ajax以JSONP技術向后台發送GET請求,上段代碼會內部處理拼接成一個新的url地址,即:http://www.s4.com:8001/users/?funcname=bbb 發給服務端。
         
    總結:
    難點:怎么從內存中拿取返回的數據。所以需要按照一定的規則來傳遞數據。
    注意點:
        - 瀏覽器只能發GET請求
        - 瀏覽器與服務端之間必須約定好方法。參數一定是動態的!!!
    JSONP是一種方式,目的解決跨域問題。每一種語言中都有。
JSONP

JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script標簽的src屬性(瀏覽器允許script標簽跨域)

除JSONP外其他的跨域操作!修改配置,讓瀏覽器的同源策略失效,所有的瀏覽器訪問都能接收到數據。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="button" onclick="Jsonp1();"  value='提交'/>
    </p>

    <p>
        <input type="button" onclick="Jsonp2();" value='提交'/>
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function Jsonp1(){
            var tag = document.createElement('script');
            tag.src = "http://c2.com:8000/test/";
            document.head.appendChild(tag);
            document.head.removeChild(tag);

        }

        function Jsonp2(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                dataType: 'JSONP',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>
JSONP實現跨域請求

CORS

隨着技術的發展,現在的瀏覽器可以支持主動設置從而允許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,相當於是通行證,使得瀏覽器允許跨域請求。

CORS --->自認為是高端操作:跨域資源共享  返回數據在響應頭中加值,讓瀏覽器放棄同源策略不在阻止。
     
隨着技術的發展,現在的瀏覽器可以支持主動設置從而允許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),
其本質是設置響應頭,相當於是通行證,使得瀏覽器允許跨域請求。
 
    內部存在機制,判斷是什么請求,若是簡單請求直接把數據返回。復雜的請求,會發兩次請求,第一次是自動發送的預檢請求option,發送的內容沒有數據,
后台預檢完畢,才會再發送帶數據的操作請求。
     
    簡單請求:
         
        def new_users(request):
            obj = HttpResponse('返回內容')
            obj['Access-Control-Allow-Origin'] = "*" 
                #設置允許跨域操作的響應頭,值為允許訪問的url地址。*代表全部。
            return obj
     
    復雜請求:
        兩次請求:
        第一次:自動發送預檢請求,沒有數據,后台做檢測允不允許這個操作。
        第二次:允許就發送帶數據的請求操作。
        def new_users(request):
 
            if request.method == "OPTIONS":
                obj = HttpResponse()
                obj['Access-Control-Allow-Origin'] = "*"
                obj['Access-Control-Allow-Methods'] = "DELETE"
                return obj
 
            obj = HttpResponse('asdfasdf')
            obj['Access-Control-Allow-Origin'] = "*"
            return obj
    注意點:兩次請求,都需要瀏覽器允許該操作!即需要添加響應頭信息。
    其他:
        - 任何請求
        詳情參見 老司機博客  http://www.cnblogs.com/wupeiqi/articles/5703697.html
CORS

練習 

JSONP跨域請求示例,代碼如下:

s4day79項目:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/js/jquery-3.2.1.js"></script>
</head>
<body>
<input type="button" value="獲取用戶列表" onclick="getUsers();">
<ul id="user_List">
    
</ul>
<script>

    //生成一個script標簽,src是要請求的地址,進行跨域操作
{#    function getUsers() {#}
{#        var tag = document.createElement("script");#}
{#        tag.src = "http://www.s4day80.com:8001/users/?funcname=bbb";#}
{#        document.head.appendChild(tag);#}
{#    }#}
    //數據返回后,自動執行自定義的函數,從內存中獲取返回的數據
{#    function bbb(arg) {#}
{#        console.log(arg);#}
{#    }#}
    //ajax發送跨域請求操作
    function getUsers() {
        // XMLHttpRequest ----->ajax發送請求,瀏覽器同源策略直接阻止。
{#        $.ajax({#}
{#            url: 'http://www.s4day80.com:8001/users/?funcname=bbb',#}
{#            type: 'GET',#}
{#            success: function (arg) {#}
{#                console.log(arg);#}
{#            }#}
{#        });#}

        // JSONP    給請求打上JSONP的標簽,這樣就不會被阻止。
        $.ajax({
            url: 'http://www.s4.com:8001/users/',
            type: 'POST',
            dataType: 'JSONP',
            jsonp: 'funcname',
            jsonpCallback: 'bbb'
        })
    }
    //同上
    function bbb(arg){
        console.log(arg);
    }
    
</script>
</body>
</html>
JSONP.html
def jsonp(request):
    return render(request,"jsonp.html")
views.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^jsonp/', views.jsonp),

]
url.py

s4day80項目下:

import json
from django.shortcuts import render,HttpResponse

def users(request):
    v = request.GET.get("funcname")
    print("請求來了....")
    user_list = ["alex","eric","egon"]
    user_list_str = json.dumps(user_list,)
    temp = "%s(%s)"%(v,user_list_str,)
    print(temp,type(temp))
    return HttpResponse(temp)
vires.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', views.users),
]
url.py

CORS跨域資源共享,示例代碼:

s4day79項目:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <input type="button" value="獲取用戶列表" onclick="getUsers();" />
    <ul id="user_list">

    </ul>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function getUsers(){
            $.ajax({
                url: 'http://www.s4.com:8001/new_users/',
                type:"DELETE",
                success:function(arg){
                    console.log(arg);
                }
            })
        }
    </script>
</body>
</html>
cors.html
def cors(request):
    return render(request,'cors.html')
views.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^cors/', views.cors),
]
url.py

s4day80項目下:

def new_users(request):
    print(request.method)

    #簡單的跨域請求
    # user_list = [
    #     'alex','eric','egon'
    # ]
    # user_list_str = json.dumps(user_list)
    # obj = HttpResponse(user_list_str)
    #
    # obj['Access-Control-Allow-Origin'] = "*"
    # return obj

    #復雜跨域請求
    if request.method == "OPTIONS":
        obj = HttpResponse()
        obj['Access-Control-Allow-Origin'] = "*"
        obj['Access-Control-Allow-Methods'] = "DELETE"
        return obj
    obj = HttpResponse('asdfasdf')
    obj['Access-Control-Allow-Origin'] = "*"
    return obj
views.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^new_users/', views.new_users),
]
url.py

 jQuery ajax()使用serialize()提交form數據


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM