1. 程式人生 > >史上最全的Ajax

史上最全的Ajax

tool 復制 last 毫秒 如何實現 mon adding ast turn

本章內容:

  • 簡介
  • 偽 AJAX
  • 原生 AJAX
  • XmlHttpRequest 的屬性、方法、跨瀏覽器支持
  • jQuery AJAX 常用方法
  • 跨域 AJAX
  • JsonP
  • CORS 簡單請求、復制請求、請求頭、cookie

一、簡介

技術分享

  AJAX 即 “Asynchronous Javascript And XML”,是指一種創建交互式網頁應用的網頁開發技術。   AJAX = 異步 JavaScript 和 XML(標準通用標記語言的子集)。   AJAX不是一種新的編程語言,而是一種用於創建更好更快以及交互性更強的Web應用程序的技術。   通過在後臺與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味著可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。
傳統的網頁(不使用 AJAX)如果需要更新內容,必須重載整個網頁頁面。

二、“偽” AJAX

所謂“偽”AJAX,是指通過<iframe>標簽局部加載內容的特性,來偽造 AJAX 請求,從而實現頁面異步更新。

那我們看看如何實現:

註:myDate.getTime() 返回時間戳,在加載地址時時間戳不變,那證明頁面局部刷新。

技術分享
<!DOCTYPE html>
<html>
 
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
 
    <body>
        <div>
            <p>請輸入要加載的地址:<span id="currentTime"></span></p>
            <p>
                <input id="url" type="text" />
                <input type="button" value="刷新" onclick="LoadPage();">
            </p>
        </div>
        <div>
            <h3>加載頁面位置:</h3>
            <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe>
        </div>
 
        <script type="text/javascript">
            window.onload
= function(){ var myDate = new Date(); document.getElementById(‘currentTime‘).innerText = myDate.getTime(); }; function LoadPage(){ var targetUrl = document.getElementById(‘url‘).value; document.getElementById(
"iframePosition").src = targetUrl; } </script> </body> </html>
“偽” AJAX 實例

  

三、原生 AJAX

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

1、XmlHttpRequest對象的主要方法與屬性

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()
    終止請求
技術分享

  

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...
技術分享

  

2、跨瀏覽器支持

  • XmlHttpRequest (IE7+, Firefox, Chrome, Opera, etc.)
  • ActiveXObject("Microsoft.XMLHTTP") (IE6, IE5)

基於原生AJAX,款瀏覽器支持的實例:

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

    <h1>XMLHttpRequest - Ajax請求</h1>
    <input type="button" onclick="XmlGetRequest();" value="Get發送請求" />
    <input type="button" onclick="XmlPostRequest();" value="Post發送請求" />

    <script src="/statics/jquery-1.12.4.js"></script>
    <script type="text/javascript">

        function GetXHR(){
            // 如果支持XMLHttpRequest就返回XMLHttpRequest,否則返回ActiveXObject
            var xhr = null;
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xhr;

        }

        function XhrPostRequest(){
            var xhr = GetXHR();
            // 定義回調函數
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 已經接收到全部響應數據,執行以下操作
                    var data = xhr.responseText;
                    console.log(data);
                }
            };
            // 指定連接方式和地址----文件方式
            xhr.open(‘POST‘, "/test/", true);
            // 設置請求頭
            xhr.setRequestHeader(‘Content-Type‘, ‘application/x-www-form-urlencoded; charset-UTF-8‘);
            // 發送請求
            xhr.send(‘n1=1;n2=2;‘);
        }

        function XhrGetRequest(){
            var xhr = GetXHR();
            // 定義回調函數
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 已經接收到全部響應數據,執行以下操作
                    var data = xhr.responseText;
                    console.log(data);
                }
            };
            // 指定連接方式和地址----文件方式
            xhr.open(‘get‘, "/test/", true);
            // 發送請求
            xhr.send();
        }

    </script>

</body>
</html>
原生AJAX--跨瀏覽器實例

四、jQuery AJAX

jQuery 既然是JavaScript的類庫,那肯定也封裝了AJAX使用相關方法,會使我們開發用起來更簡單。

jQuery Ajax的本質無疑是 XMLHttpRequest 或 ActiveXObject

註:2.+的版本不再支持IE9以下的瀏覽器

jQuery 相關知識戳這

jQuery Ajax 常用方法有三個:get、post、ajax:

技術分享
# jQuery Ajax 常用方法列表

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.ajax(...)
    部分參數:
            url:請求地址
           type:請求方式,GET、POST(1.9.0之後用method)
        headers:請求頭
           data:要發送的數據
    contentType:即將發送信息至服務器的內容編碼類型(默認: "application/x-www-form-urlencoded; charset=UTF-8")
          async:是否異步
        timeout:設置請求超時時間(毫秒)

     beforeSend:發送請求前執行的函數(全局)
       complete:完成之後執行的回調函數(全局)
        success:成功之後執行的回調函數(全局)
          error:失敗之後執行的回調函數(全局)

        accepts:通過請求頭發送給服務器,告訴服務器當前客戶端課接受的數據類型
       dataType:將服務器端返回的數據轉換成指定類型
                   "xml": 將服務器端返回的內容轉換成xml格式
                  "text": 將服務器端返回的內容轉換成普通文本格式
                  "html": 將服務器端返回的內容轉換成普通文本格式,在插入DOM時,如果包含js標簽,會嘗試去執行
                "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回調函數
技術分享 技術分享
# jQuery Ajax 方法列表

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:設置請求超時時間(毫秒)

     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 更多方法 技術分享
# 基於jQueryAjax - Demo

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

    <p>
        <input type="button" onclick="XmlSendRequest();" value=‘Ajax請求‘ />
    </p>


    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>

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


    </script>
</body>
</html>
jQuery Ajax 實例

五、跨域 AJAX

跨域,首先要明白瀏覽器同源策略機制,那什麽是同源策略機制?

同源策略阻止從一個源加載的文檔或腳本中獲取或設置另一個源加載的文檔的屬性。

:同源策略是瀏覽器的限制,所以請求的發送和響應都是可以進行的,只是瀏覽器不接收,是瀏覽器不接收,是瀏覽器不接收,重要的事說三遍。

瀏覽器的同源策略並不是對所有的請求都限制:一般情況對 XmlHttpRequest 限制,但對 img、iframe、script等具有src屬性的標簽不起作用。

跨域,即跨域名訪問,如:http://www.test1.com 域名向 ttp://www.test2.com 域名發送請求。

Jsonp 與 CORS 的比較:

  • Jsonp:只支持 GET 請求,CORS支持所有類型的HTTP請求。
  • JSONP 的優勢在於支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。

1、JSONP 實現跨域請求

JSONP(JSONP - JSON with Padding 是 JSON 的一種 “使用模式” ),這種模式使用比較普遍。

原理上是利用 script 標簽的 src 屬性,因為同源策略對 scropt 的 src 屬性不起作用。

JSONP 的實例:

註:Jsonp1為 jsonp 的本質;Jsonp2 指定datatype 內部會運行 Jsonp1 ,返回 func ,執行 func 函數。

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

    <p><input type="button" onclick="Jsonp1();"  value=‘提交1‘/></p>
    <p><input type="button" onclick="Jsonp2();" value=‘提交2‘/></p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function func(arg) {
            // func 為請求傳過來的函數名 func([1,2,3]);
            console.log(arg)
        }

        function Jsonp1(){
            // JSONP 的本質
            var tag = document.createElement(‘script‘);
            tag.src = "http://nick.com:8001/index";
            document.head.appendChild(tag);
            document.head.removeChild(tag);
        }

        function Jsonp2(){
            $.ajax({
                url: "http://nick.com:8001/index",
                type: ‘GET‘,
                dataType: ‘JSONP‘,
                jsconCallBack: "func"   // 執行func函數
            })
        }

    </script>
</body>
</html>
技術分享
// 請求的地址返回值

    def get(self, *args, **kwargs):
        self.write(‘func([1,2,3]);‘)

2、CORS

跨域的第二套解決方案:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,使得瀏覽器允許跨域請求。

請求分為兩類:

簡單請求 和 非簡單請求

技術分享
條件:
    1、請求方式:HEAD、GET、POST
    2、請求頭信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 對應的值是以下三個中的任意一個
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
 
註意:同時滿足以上兩個條件時,則是簡單請求,否則為復雜請求
技術分享

* 簡單請求和非簡單請求的區別?

簡單請求:一次請求
非簡單請求:兩次請求,在發送數據之前會先發一次請求用於做“預檢”,只有“預檢”通過後才再發送一次請求用於數據傳輸。

* 什麽是“預檢”?

技術分享
- 請求方式:OPTIONS
- “預檢”其實做檢查,檢查如果通過則允許傳輸數據,檢查不通過則不再發送真正想要發送的消息
- 如何“預檢”
     => 如果復雜請求是PUT等請求,則服務端需要設置允許某請求,否則“預檢”不通過
        Access-Control-Request-Method
     => 如果復雜請求設置了請求頭,則服務端需要設置允許某請求頭,否則“預檢”不通過
        Access-Control-Request-Headers
技術分享

基於cors實現AJAX請求:

a、支持跨域,簡單請求

服務器設置響應頭:Access-Control-Allow-Origin = ‘域名‘ 或 ‘*‘,* 為所有

具體見以下實例:

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

    <p><input type="submit" onclick="XmlSendRequest();" /></p>
    <p><input type="submit" onclick="JqSendRequest();" /></p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open(‘GET‘, "http://nick.com:8000/test/", true);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://nick.com:8000/test/",
                type: ‘GET‘,
                dataType: ‘text‘,
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }

    </script>
</body>
</html>
HTML 技術分享
    def get(self):
// 允許哪個域名
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.write(‘{"status": true, "data": "nick"}‘)
server

b、支持跨域,復雜請求

對於復雜請求,先會發送“預檢”請求,如果“預檢”成功,第二次則發送真實數據,共分兩次發送數據。

  • “預檢”請求時,允許請求方式則需服務器設置響應頭:Access-Control-Request-Method
  • “預檢”請求時,允許請求頭則需服務器設置響應頭:Access-Control-Request-Headers,
  • “預檢”緩存時間,服務器設置響應頭:Access-Control-Max-Age,單位秒,即多少秒內不用發出另一條預檢請求

具體見以下實例:

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

    <p><input type="submit" onclick="XmlSendRequest();" /></p>
    <p><input type="submit" onclick="JqSendRequest();" /></p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open(‘PUT‘, "http://nick.com:8000/test/", true);
            xhr.setRequestHeader(‘k1‘, ‘v1‘);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://nick.com:8000/test/",
                type: ‘PUT‘,
                dataType: ‘text‘,
                headers: {‘k1‘: ‘v1‘},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }

    </script>
</body>
</html>
HTML 技術分享
    def put(self):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.write(‘{"status": true, "data": "nick"}‘)

    def options(self, *args, **kwargs):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.set_header(‘Access-Control-Allow-Headers‘, "k1,k2")
        self.set_header(‘Access-Control-Allow-Methods‘, "PUT,DELETE")
        self.set_header(‘Access-Control-Max-Age‘, 10)
server

c、跨域獲取響應頭

默認獲取到的所有響應頭只有基本信息,如果想要獲取自定義的響應頭,則需要在服務端設置 Access-Control-Expose-Headers

具體見以下實例:

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

    <p><input type="submit" onclick="XmlSendRequest();" /></p>
    <p><input type="submit" onclick="JqSendRequest();" /></p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                    // 獲取響應頭
                    console.log(xhr.getAllResponseHeaders());
                }
            };
            xhr.open(‘PUT‘, "http://nick.com:8000/test/", true);
            xhr.setRequestHeader(‘k1‘, ‘v1‘);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://nick.com:8000/test/",
                type: ‘PUT‘,
                dataType: ‘text‘,
                headers: {‘k1‘: ‘v1‘},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                    // 獲取響應頭
                    console.log(xmlHttpRequest.getAllResponseHeaders());
                }
            })
        }

    </script>
</body>
</html>
HTML 技術分享
    def put(self):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")

        self.set_header(‘name‘, "nick")
        self.set_header(‘age‘, "18")

        self.set_header(‘Access-Control-Expose-Headers‘, "name,age")

        self.write(‘{"status": true, "data": "nick"}‘)

    def options(self, *args, **kwargs):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.set_header(‘Access-Control-Allow-Headers‘, "k1,k2")
        self.set_header(‘Access-Control-Allow-Methods‘, "PUT,DELETE")
        self.set_header(‘Access-Control-Max-Age‘, 10)
server

d、跨域傳輸cookie

默認情況在跨域請求中,HTTP Authentication的信息,Cookie頭以及用戶的SSL證書無論在預檢請求中或是在實際請求中都是不會被發送

如果想要發送,需要相應設置:

  • 瀏覽器端:XMLHttpRequest的withCredentials 為true
  • 服務器端:Access-Control-Allow-Credentials 為true
  • 註意:服務器端響應的 Access-Control-Allow-Origin 不能是通配符 *

具體見以下實例:

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

    <p><input type="submit" onclick="XmlSendRequest();" /></p>
    <p><input type="submit" onclick="JqSendRequest();" /></p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };

            xhr.withCredentials = true;

            xhr.open(‘PUT‘, "http://nick.com:8000/test/", true);
            xhr.setRequestHeader(‘k1‘, ‘v1‘);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://nick.com:8000/test/",
                type: ‘PUT‘,
                dataType: ‘text‘,
                headers: {‘k1‘: ‘v1‘},
                xhrFields:{withCredentials: true},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }

    </script>
</body>
</html>
HTML 技術分享
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.set_header(‘Access-Control-Allow-Credentials‘, "true")
        
        self.set_header(‘name‘, "nick")
        self.set_header(‘age‘, "18")
        self.set_header(‘Access-Control-Expose-Headers‘, "name,age")

        self.set_cookie(‘_k‘, ‘_v‘);

        self.write(‘{"status": true, "data": "nick"}‘)

    def options(self, *args, **kwargs):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.set_header(‘Access-Control-Allow-Headers‘, "k1,k2")
        self.set_header(‘Access-Control-Allow-Methods‘, "PUT,DELETE")
        self.set_header(‘Access-Control-Max-Age‘, 10)
server

史上最全的Ajax