jacascript AJAX 學習

来源:https://www.cnblogs.com/sspeng/archive/2018/03/14/7648620.html
-Advertisement-
Play Games

前言:這是筆者學習之後自己的理解與整理。如果有錯誤或者疑問的地方,請大家指正,我會持續更新! AJAX 是 asynchronous javascript and XML 的簡寫,就是非同步的 javascript 和 XML。這一技術能夠向伺服器請求額外的數據而無須刷新整個頁面,會帶來更好的用戶體驗 ...


前言:這是筆者學習之後自己的理解與整理。如果有錯誤或者疑問的地方,請大家指正,我會持續更新!

  AJAX 是 asynchronous javascript and XML 的簡寫,就是非同步的 javascript 和 XML。這一技術能夠向伺服器請求額外的數據而無須刷新整個頁面,會帶來更好的用戶體驗。雖然名字中包含 XML,但是 ajax 通信與數據格式無關

 

創建對象

  因為 XMLHTTPRequest() 是一個構造函數,所以需要實例化一個 XMLHttpRequset 對象。下麵是創建XHR對象的相容寫法;

  如果要建立多個不同的請求,就要實例化多個不同的 XMLHttpRequset 對象;

        <script type="text/javascript">
            var xhr;
            if(window.XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject('Microsoft.XMLHTTP');
            }
        </script>

 

發送請求

  要想把請求發送到伺服器,我們就需要使用 open() 方法和 send() 方法。

open()

  open() 方法需要三個參數:

       xhr.open("GET","test.json",true);

  第一個參數定義發送請求所使用的方法("GET" 還是 "POST"),不區分大小寫,但通常使用大寫字母,記得帶引號。

  "GET" 用於常規請求,它適用於當 URL 完全指定請求資源,當請求對伺服器沒有任何副作用以及當伺服器的響應是可緩存的情況下。

  然而,在以下情況中,請使用 "POST" 請求:

  • 無法使用緩存文件(更新伺服器上的文件或資料庫)
  • 向伺服器發送大量數據("POST" 沒有數據量限制)
  • 發送包含未知字元的用戶輸入時,"POST" 比 "GET"更穩定也更可靠

  第二個參數規定伺服器端腳本的 URL(該文件可以是任何類型的文件,比如 .txt 和 .xml,或者伺服器腳本文件,比如 .asp 和 .php (在傳迴響應之前,能夠在伺服器上執行任務)。

  第三個參數規定是否非同步發送請求的布爾值,如果不填寫,預設為 true,表示非同步發送。如果接受的是同步響應,則需要將 open()方法的第三個參數設置為 false,那麼 send()方法將阻塞直到請求完成。客戶端 javascript 是單線程的,當 send() 方法阻塞時,它通常會導致整個瀏覽器界面凍結。如果連接的伺服器響應慢,那麼用戶的瀏覽器將凍結,所以應該避免使用同步。

send()

  send() 方法接收一個參數,即要作為請求主體發送的數據。調用 send() 方法後,請求被分派到伺服器。

  如果是 "GET" 方法,send() 方法無參數,或參數為 null;如果是 "POST" 方法,send() 方法的參數為要發送的數據。

            xhr.open("GET","test.json",false);
            xhr.send(null);

GET

  "GET" 用於常規請求,它適用於當 URL 完全指定請求資源,當請求對伺服器沒有任何副作用以及當伺服器的響應是可緩存的情況下。

  【數據發送】

  使用 "GET" 方式發送請求時,數據被追加到 open() 方法中 URL 的末尾,可以直接看到,存在安全隱患。

  數據以問號開始,名和值之間用等號鏈接,名值對之間用和號(&)分隔。使用 "GET" 方式發送的數據常常被稱為查詢字元串。

  【編碼】

  由於 URL無法識別特殊字元,所以如果數據中包含特殊字元(如中文),則需要進行編碼,編碼的方式有很多種,其中 encodeURIComponent() 函數可把字元串作為 URI 組件進行編碼。該方法主要對 ;/?:@&=+$,# 等這些用於分隔URI組件的字元以及中文進行編碼。由於此方法對 :/ 都進行了編碼,所以不能用它來對網址進行編碼,而適合對 URI 中的參數進行編碼

  在 "GET" 請求中,為了避免緩存的影響,可以向 URL 末尾添加一個隨機數或時間戳。

    <script>
        var url = 'test.php' +'?name=' + encodeURIComponent("你好");
        xhr.open('GET',url+'&'+Number(new Date()),true);
        xhr.send(null);
    </script>

POST

  "POST" 請求通常用於向伺服器發送應該被保存的數據。"POST" 方法常用於 HTML 表單。它在請求主體中包含額外數據且這些數據常存儲到伺服器上的資料庫中。

  在 open() 方法第一個參數的位置傳入"POST",就可以初始化一個 "POST" 請求。

  【設置請求頭】

  預設情況下,伺服器對 "POST" 請求和提交表單的請求並不會一視同仁。因此,伺服器端必須有程式來讀取發送過來的原始數據,並從中解析出有用的部分。不過,可以使用 XHR 來模仿表單提交:首先將 content-Type 頭部信息設置為 application/x-www-form-urlencoded,也就是表單提交時的內容類型;

  使用 setRequestHeader() 方法可以設置自定義的請求頭部信息。這個方法接受兩個參數:頭部欄位的名稱頭部欄位的值。要成功發送請求頭部信息,必須在調用 open()方法之後且調用 send() 方法之前調用 setRequestHeader() 方法 。

  在項目中,又是需要驗證用戶登錄,可以設置請求頭驗證。機制就是:在用戶首次登錄成功之後,伺服器發送token到客戶端,客戶端存入cookie。用戶做任何請求操作時,在 ajax的請求頭裡帶上 token,用以 server-end 做登錄狀態驗證。

  【發送主體】

  發送 "POST" 請求的第三步就是向 send() 方法中傳入某些數據,這一點和 "GET" 請求不一樣。由於 XHR 最初的設計主要是為了處理 XML,因此可以在此傳入 XML DOM 文檔,傳入的文檔經序列化之後將作為請求主體被提交到伺服器。當然,也可以在此傳入任何想發送到伺服器的字元串。

  接下來要以適當的格式創建一個字元串,並使用 send() 方法發送。

  "POST" 數據的格式與 "GET" 數據的格式相同,名和值之間用等號鏈接,名值對之間用和號(&)分隔。

  【編碼】

  由於使用 "POST" 方式傳遞數據時,需要設置請求頭 "content-type",這一步驟已經能夠自動對特殊字元(如中文)進行編碼,所以就不再需要使用 encodeURIComponent() 方法了。

  "POST" 請求主要用於數據提交,相同 URL 的重覆 "POST" 請求從伺服器得到的響應可能不同,所以不應該緩存使用 "POST" 方法的請求。

  "GET" 對所發送信息的數量有限制,一般在2000個字元。與 "GET" 請求相比,"POST" 請求消耗的資源會更多一些。從性能角度來看,以發送相同的數據計,"GET" 請求的速度最多可"POST"請求的兩倍。

    <script>
        xhr.open('POST',url,true);
        //設置請求頭
        xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
        //拼接數據
        var strData = 'name="abc"&num=123';
        //發送請求
        xhr.send(strData);
    </script>

 

接收響應

  一個完整的 HTTP 響應由狀態碼、響應頭集合和響應主體組成。

  在收到響應後,這些都可以通過 XMLHttpRequset 對象的屬性和方法使用,主要有以下4個屬性:

responseText 作為響應主體被返回的文本(文本格式)
responseXML 如果響應的內容類型是 "text/xml" 或 "application/xml",這個屬性中將保存著響應數據的 XML DOM 文檔(document 格式)
status HTTP狀態碼(數字形式)
statusText HTTP狀態說明(文本格式)

 

  在接收到響應後,第一步是檢查 status 屬性,以確定響應已經成功返回。一般來說,可以將 HTTP 狀態碼為 200 作為響應成功的標誌。此時,responseText 屬性的內容已經就緒,而且在內容類型正確的情況下,responseXML 也可以訪問了。此外,狀態碼為 304 表示請求的資源並沒有被修改,可以直接使用瀏覽器中緩存的版本;當然,也意味著響應是有效的

  無論內容類型是什麼,響應主體的內容都會保存到 responseText 屬性中,而對於非 XML 數據而言,responseXML 屬性的值將為 null;

            if((xhr.status >=200 && xhr.status < 300) || xhr.status == 304){
                alert(xhr.responseText);
            }else{
                alert('請求失敗,響應代碼為:' + xhr.status);
            }

 

非同步響應和同步響應

  如果不設置 open() 方法的第三個參數(預設為true,即非同步響應)。

  如果接收的是非同步響應,這就需要檢測 XMLHttpRequset 對象的 readyState 屬性,該屬性表示 請求/響應 過程的當前活動階段。這個屬性可取的值如下:

0(UNSENT) 未初始化 還沒調用open()
1(OPEND) 啟動 已經調用open() ,但還沒調用 send()
2(HEADERS_RECEIVED) 發送 己經調用 send() 方法,且接收到頭信息。
3(LOADING) 正在接收 已經接收到部分響應主體信息。
4(DONE) 完成 已經接收到全部響應數據,而且已經可以在客戶端使用了。

 

  理論上,只要 readyState 屬性值由一個值變成另一個值,都會觸發一次 readystatechange 事件。可以利用這個事件來檢測每次狀態變化後 readyState 的值。通常,我們對readyState 值為4的階段感興趣,因為這時所有數據都已就緒。

  必須在調用 open() 之前指定 onreadystatechange 事件處理程式才能確保跨瀏覽器相容性,否則將無法接收 readyState 屬性為0和1的情況

            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status == 200){
                        alert(xhr.responseText);
                    }
                }
            }

  如果將 open() 方法的第三個參數設置為 false,接收的就是同步響應,那麼 send() 方法將阻塞直到請求完成。一旦 send() 返回,僅需要檢查 XHR對象的 status 和responseText 屬性即可。

  應該避免使用同步請求。客戶端 javascript 是單線程的,當 send() 方法阻塞時,它通常會導致整個瀏覽器 UI 凍結。如果連接的伺服器響應慢,那麼用戶的瀏覽器將凍結,用戶體驗非常不好。

 

進度事件

  一般地,使用 readystatechange 事件探測 HTTP 請求的完成。XHR2 規範草案定義了進度事件 Progress Events 規範,XMLHttpRequest 對象在請求的不同階段觸發不同類型的事件,所以它不再需要檢査 readyState 屬性。

  有以下6個進度事件:

  1. loadstart: 在接收到響應數據的第一個位元組時觸發
  2. progress: 在接收響應期間持續不斷地觸
  3. error: 在請求發生錯誤時觸發
  4. abort: 在因為調用abort()方法而終止連接時觸發
  5. load: 在接收到完整的響應數據時觸發
  6. loadend: 在通信完成或者觸發error、abort或load事件後觸發
  7. timeout: 超時發生時觸發

  每個請求都從觸發 loadstart 事件開始,接下來,通常每隔50毫秒左右觸發一次 progress 事件,然後觸發 load、error、abort 或 timeout 事件中的一個,最後以觸發 loadend 事件結束

  對於任何具體請求,瀏覽器將只會觸發 load、abort、timeout 和 error 事件中的一個。XHR2規範草案指出一旦這些事件中的一個發生後,瀏覽器應該觸發 loadend 事件。

load

  響應接收完畢後將觸發 load 事件,因此也就沒有必要去檢查 readyState 屬性了。但一個完成的請求不一定是成功的請求,例如,onload 事件的處理程式應該檢查 XMLHttpRequest 對象的 status 狀態碼來確定收到的是“200 OK”而不是“404 Not Found”的HTTP響應

progress

  progress 事件會在瀏覽器接收新數據期間周期性地觸發。而 onprogress 事件處理程式會接收到一個 event 對象,其 target 屬性是 XHR 對象,但包含著三個額外的屬性:lengthComputable、loaded 和t otal。其中,lengthComputable 是一個表示進度信息是否可用的布爾值,loaded 表示已經接收的位元組數,total 表示根據 Content-Length 響應頭部確定的預期位元組數。有了這些信息,就可以為用戶創建一個進度指示器了。

上傳進度upload

  除了為監控 HTTP 響應的載入定義的這些有用的事件外,XHR2 也給出了用於監控 HTTP 請求上傳的事件。在實現這些特性的瀏覽器中,XMLHttpRequest 對象將有 upload 屬性。upload 屬性值是一個對象,它定義了 addEventListener() 方法和整個 progress 事件集合,比如 onprogress 和 onload。但 upload 對象沒有定義 onreadystatechange 屬性,upload  僅能觸發新的事件類型。

    <input type="file" name="file1" id="file1" style="display:none">
    <button id="btn">上傳文件</button>
    <div id="pro"></div>
    <div id="result"></div>
    <script>
        btn.onclick = function(){
            file1.click();
            pro.innerHTML = result.innerHTML = '';
        }
        file1.onchange = function(){
            //創建xhr對象
            var xhr = new XMLHttpRequest();
            var data = file1.files[0];
            //上傳事件
            xhr.upload.onprogress = function(e){
                e = e || event;
                if (e.lengthComputable){
                    pro.innerHTML = "上傳進度為:" + e.loaded + " of " + e.total + " bytes" + ';百分比為:' + e.loaded/e.total;
                }
            }
            xhr.onload = function(e){
                var data = xhr.responseText;
                e = e || event;
                if(xhr.status == 200){
                    result.innerHTML =  data;
                }
            };
            //發送請求
            xhr.open('post','pp.php',true);
            xhr.setRequestHeader("content-type",data.type);
            xhr.send(data);
        }
        </script>

 

超時、中止、錯誤事件

  HTTP 請求無法完成有3種情況。如果請求超時,會觸發 timeout 事件。如果請求中止,會觸發 abort 事件。最後,像太多重定向這樣的網路錯誤會阻止請求完成,但這些情況發生時會觸發 error 事件。

  可以通過調用 XMLHttpRequest 對象的 abort() 方法來取消正在進行的 HTTP 請求。調用 abort() 的主要原因是完成取消或超時請求消耗的時間太長或當響應變得無關時。

  XHR對象的 timeout 屬性等於一個整數,表示多少毫秒後,如果請求仍然沒有得到結果,就會自動終止。該屬性預設等於0,表示沒有時間限制。如果請求超時,將觸發ontimeout 事件。

    <script>
        var xhr = new XMLHttpRequest();
        btn.onclick = function(){
            xhr.abort();
        }
        xhr.onabort = function(){
            console.log("請求已終止");
        }

        xhr.ontimeout = function(){
            console.log('請求超時');
        }
        xhr.timeout = 3000;
        
        xhr.onerror = function(){
            console.log("請求報錯");    
        }
        xhr.onloadend = function(){
            console.log("請求結束");    
        }
    </script>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 入坑iOS開發這麼久,一直都是在模擬器上運行,公司的項目也都有公司的開發者賬號進行真機調試。但是很多時候在網上download一些demo想在真機上運行看一下效果的時候都沒法成行,今天抽空好好研究和學習了一下在最新的xcode9上如何進行無證書真機調試,過程其實很簡單,下麵我們來瞭解一下整個過程。 ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 在實際開發過程中經常在按鈕上添加文字和圖片,位置和圖片的位置根據需求放置也是不一樣的。下麵實現了各種顯示方式,如下圖: UIButton+LSAdditions.h UIButton+LSAdditions.m 現在測試代碼如下: ...
  • 崩潰分析方式:命令行解析Crash文件 通過Mac自帶的命令行工具解析Crash文件需要具備三個文件 symbolicatecrash,Xcode自帶的崩潰分析工具,使用這個工具可以更精確的定位崩潰所在的位置,將0x開頭的地址替換為響應的代碼和具體行數。 我們打包時產生的dSYM文件。 崩潰時產生的 ...
  • id類型是一個通用類型,OC使用id表示任意類型的對象,它可以作為一個占位符表示這是一個不確定的類型的對象或者引用。因此,所有的對象都 可以用id來表示。這很有用,想象一下,如果你需要實現一個通用的鏈表類,你可以將鏈表結點中的數據欄位的類型聲明為id類型,那麼你就可以往這個鏈表中存放任意類型的對象了 ...
  • textView用於顯示文本,大量文字顯示在一起顯得過於緊湊。可通過在佈局中更改TextView屬性設置行間距。 1、android:lineSpacingMultiplier="1.5" 表示1.5倍行距 2、android:lineSpacingExtra="3dp" 表示行間距離為3dp 有時 ...
  • 作者:ManfredHu 鏈接:http://www.manfredhu.com/2018/03/15/31-laya-game-tips/index.html 聲明:版權所有,轉載請保留本段信息,謝謝大家 LayaBox Web前端最近都在跨界!!現在又伸手到游戲領域了。但是真的那麼好跨界嗎?請讓 ...
  • 之前在看對象的api中for in函數時,有一個地方讓我略有疑惑: 為什麼是obj[key]而不是obj.key呢?我們在瀏覽器試一下: 說起來也有點尷尬,原來在for in函數中,得到的key是一個字元串類型,所以只能用obj[key],其實,比如說在這個對象中,obj.x和obj["x"]是完全 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...