#hello,JS:13-01技術(shù)方案:Ajax 使用和原理

前端和后端如何交互,從網(wǎng)站的層面上,如何去呈現(xiàn)?如何和后端去交互?如何向后端獲取數(shù)據(jù)和請求?需要一種方法。

一、頁面如何和后端交互

幾種方法:

1、form表單提交:

form表單提交實例

如我們把method改為get,用get方法拼裝成一個帶有用戶名和密碼的新的url地址,向服務器去發(fā)送請求,相應關(guān)鍵信息(用戶名和密碼)都會傳遞給服務器,進行處理;post則是直接將這些關(guān)鍵信息直接發(fā)給服務器(而不是通過url傳遞),后臺監(jiān)聽到數(shù)據(jù)直接處理。

這里涉及了get和post的處理。請回看:

miya Wang:淺談HTML表單(一):表單提交原理(涉及post和get)

這種表單提交的交互方式,提交時頁面發(fā)生跳轉(zhuǎn)即出現(xiàn)新的頁面,體驗感不好;再者,頁面提交為單向提交,后臺給什么反饋?反應?均不知道什么結(jié)果。

2、websocket

3、ajax

二、Ajax

1、定義:

Ajax,即AsynchronousJavaScript+XML,是一種依賴前端元素獲取數(shù)據(jù)的方法,它是一種技術(shù)方案(不是一種新技術(shù)),Ajax主要通過XMLHttpRequest這個瀏覽器的內(nèi)置對象向服務器發(fā)出HTTP請求,并接收HTTP響應,實現(xiàn)在頁面不刷新情況下和服務端進行數(shù)據(jù)交互。

2、交互形式

Ajax一般用xml格式數(shù)據(jù)進行數(shù)據(jù)交互,現(xiàn)今ajax與服務器交互則是傾向于JSON格式規(guī)范數(shù)據(jù)格式,后端可以發(fā)任何格式的數(shù)據(jù)格式。

伴隨著瀏覽器(chrome)升級(IE6-10),從原本依賴現(xiàn)有的CSS/HTML/Javascript去向服務器發(fā)送請求到現(xiàn)在最核心依賴瀏覽器提供的XMLHttpRequest對象(使用JS操作這個對象獲取相應的響應,得到數(shù)據(jù)),即

控制臺操作XMLHttpRequest、fetch,可顯示它們均是瀏覽器的內(nèi)置對象


image

三、如何實現(xiàn)Ajax

  • XMLHttpRequest
  • fetch(注意兼容性使用can i use)

實現(xiàn)基本方式:

<script>
        
        var xhr = new XMLHttpRequest()
        xhr.open('GET','/1.json',true)
        xhr.send()
        var data = xhr.responseText
        console.log(data)
</script>

1、通過get方式去請求

(1)通過js去寫XMLHttpRequest來設置ajax

//1.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
    var xhr = new XMLHttpRequest()// XMLHttpRequest()是一個函數(shù),通過new的方式去生成一個對象
        xhr.open('GET','/1.json',true)// 做一些設置:發(fā)請求,發(fā)給誰?/有post或者get方式/同步異步;設置ajax:請求的方法,請求的服務器(或資源),異步方式(true)
        xhr.send()
    </script>
</body>
</html>

控制臺顯示一個報錯:

image

報錯顯示無法與當前服務器交互,只能通過跨域請求。請求必須以http或者https開頭的json格式文件,即所請求的服務器為

'https//1.json'

解決方法:通過http-server服務器去發(fā)請求,獲取數(shù)據(jù)

打開該文件的終端,通過終端打開http-server


image

然后輸入帶有剛才文件名的服務器地址:http://127.0.0.1:8081/1.html 隨即出現(xiàn)以下報錯,

image

由于還沒設置后端數(shù)據(jù)文件,點開鏈接出現(xiàn)找不到該網(wǎng)頁(404):


image

接下來如何解決:通過模擬數(shù)據(jù),創(chuàng)建一個1.json的文件

{
    "name":"wangxiaoqin"
    "age" : 1
}

然后網(wǎng)頁打開服務器的json格式地址:http://127.0.0.1:8081/1.json
即出現(xiàn)

image

打開html的服務器網(wǎng)頁控制臺,看到json數(shù)據(jù)通過ajax獲取到


image

此時,我們拿到數(shù)據(jù),并沒有在js中操作如何拿到數(shù)據(jù),是同步?異步?

第1種:同步的時候,如何拿到數(shù)據(jù)?
注:此方法為同步,造成網(wǎng)頁一直在計算中,不能前進 ,可能造成頁面卡死狀態(tài)
代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        var xhr = new XMLHttpRequest()
                xhr.open('GET','/1.json',false) //設置同步
                xhr.send()

                var data = xhr.responseText
                console.log(data)

    </script>
</body>
</html>

此時控制臺console響應,數(shù)據(jù)到來,并通知到如圖:


image

總結(jié):

  • 如果是同步的方式執(zhí)行代碼,代碼一行行執(zhí)行,到xhr.send()的時候,代碼執(zhí)行就暫停,漫長地等待著數(shù)據(jù)的到來,數(shù)據(jù)到來之后通過 xhr.responseText拿到數(shù)據(jù)。
  • 設置一個ajax:創(chuàng)建對象——參數(shù)設置——發(fā)送——數(shù)據(jù)到來——拿到數(shù)據(jù)

第2種:異步的方式獲取數(shù)據(jù)
代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        var xhr = new XMLHttpRequest()
                xhr.open('GET','/1.json',true)//異步方式
                xhr.send()
        
                xhr.addEventListener('load',function(){
                var data = xhr.responseText
                console.log(data)
               })
      
       // 或者 
       // xhr.onload = function(){
       //     var data = xhr.responseText
      //      console.log(data)
     //     }

    </script>
</body>
</html>

此時控制臺console響應,數(shù)據(jù)到來,并通知到,如圖:


image

(2)通過狀態(tài)碼/狀態(tài)值獲取數(shù)據(jù)
A、添加status(狀態(tài)碼)方式獲取【與onload事件相對應】

當我修改代碼中json數(shù)據(jù)文件名:

js中添加一個console.log(xhr.status) (狀態(tài)碼)
范例代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>        
        var xhr = new XMLHttpRequest()
                xhr.open('GET','/1a.json',true)//修改json文件名
                xhr.send()
                xhr.addEventListener('load',function(){
                //添加狀態(tài)碼:
            console.log(xhr.status)
            var data = xhr.responseText
            console.log(data)
        })
      
       // 或者 
       // xhr.onload = function(){
       //     var data = xhr.responseText
      //      console.log(data)
       // }

    </script>
</body>
</html>

執(zhí)行結(jié)果如下:將json文件名修改,造成了控制臺報錯。即明知道出錯,但卻一無所知


image

不修改json文件名

代碼如下:

//1.json
<script>
        var xhr = new XMLHttpRequest()
        xhr.open('GET','/1.json',true)//不修改json文件名
        xhr.send()
        xhr.addEventListener('load',function(){
        console.log(xhr.status)
    var data = xhr.responseText
    console.log(data)
        })
</script>

如圖:


image

總結(jié):控制臺出現(xiàn)狀態(tài)碼的響應,返回后端設置的相應數(shù)據(jù)

  • 狀態(tài)碼200,表示這個文件存在;
  • 狀態(tài)碼404,表示這個文件不存在;
  • 狀態(tài)碼503,服務器表示收到請求,但內(nèi)部自己報錯了,未返回合理的數(shù)據(jù);
  • 狀態(tài)碼304,表示服務器是進行了緩存狀態(tài)

當1.json時,

//1.json
<script>        
    var xhr = new XMLHttpRequest()
        xhr.open('GET','/1.json',true)
        xhr.send()
        xhr.addEventListener('load',function(){
        console.log(xhr.status)
       //當狀態(tài)碼為200時,獲取這個數(shù)據(jù)
            if(xhr.status ===200){
                  var data = xhr.responseText
              console.log(data)
            }else{
              console.log('error')
            }        
        })
</script>

結(jié)果如圖:


image

當1a.json時,

//1a.json
<script>        
    var xhr = new XMLHttpRequest()
        xhr.open('GET','/1a.json',true)
        xhr.send()
        xhr.addEventListener('load',function(){
        console.log(xhr.status)
       //當狀態(tài)碼為200時,獲取這個數(shù)據(jù)
            if(xhr.status ===200){
                    var data = xhr.responseText
                console.log(data)
            }else{
                console.log('error')
            }        
        })
</script>

如圖:


image

比較完整地在設置多個狀態(tài)碼條件下,ajax該如何向后臺要取數(shù)據(jù),完整代碼如下

//1.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
   <body>
    <script>        
    var xhr = new XMLHttpRequest()
        xhr.open('GET','/1a.json',true)
        xhr.send()
        xhr.addEventListener('load',function(){
        console.log(xhr.status)
        if((xhr.status >= 200 && xhr.status <300) ||xhr.status ===304){
                var data = xhr.responseText
            console.log(data)
            }else{
            console.log('error')
            }           
        })
        </script>
   </body>
</html>

//數(shù)據(jù)文件:1.json

{
    "name":"wangxiaoqin"
    "age" : 1
}

B、使用readyState(狀態(tài)值)方式獲取數(shù)據(jù)【與onreadystatechange事件相對應】
js中添加另一種狀態(tài):readyState

綁定事件獲取方法:
(1)on+一個事件
(2)addEventListener綁定一個函數(shù)事件

范例代碼如下:

//1.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>    
    var xhr = new XMLHttpRequest()
        xhr.open('GET','/1.json',true)
        xhr.send()

       // 使用readyStatechange方法
        console.log('readyState:',xhr.readyState)
        xhr.addEventListener('readystatechange',function(){
            console.log('readyState:',xhr.readyState)
        })
       
        // 或者xhr.onreadystatechange = function(){
        //    console.log('readyState:',xhr.readyState)
        // }

        xhr.addEventListener('load',function(){
            console.log(xhr.status)
            if((xhr.status >= 200 && xhr.status <300) ||xhr.status ===304){
                var data = xhr.responseText
                console.log(data)

            }else{
                console.log('error')
            }
            
        })
      
       // // 或者 
       // xhr.onload = function(){
       //      var data = xhr.responseText
          //  console.log(data)
       // }

          xhr.onerror = function(){
            console.log('error')
          }

    </script>
</body>
</html>

控制臺如圖:


image

對象中有一個狀態(tài)值:readyState,這個狀態(tài)與后端交互時,該狀態(tài)會發(fā)生幾次改變,每次改變都會觸發(fā)該狀態(tài)的change事件,每次監(jiān)聽這個事件,則輸出readyState。即第一次請求狀態(tài)改變?yōu)?,當觸發(fā)change事件的時候,則開始變化:readyState2,3,4

總結(jié):AJAX實際運行中的幾種狀態(tài)值:
AJAX實際運行當中,對于訪問XMLHttpRequest(XHR)時并不是一次完成的,而是分別經(jīng)歷了多種狀態(tài)后取得的結(jié)果,對于這種狀態(tài)在AJAX中共有5種,分別是:
0 - (未初始化)還沒有調(diào)用send()方法
1 - (載入)已調(diào)用send()方法,正在發(fā)送請求
2 - (載入完成)send()方法執(zhí)行完成,
3 - (交互)正在解析響應內(nèi)容
4 - (完成)響應內(nèi)容解析完成,可以在客戶端調(diào)用了
對于上面的狀態(tài),其中“0”狀態(tài)是在定義后自動具有的狀態(tài)值,而對于成功訪問的狀態(tài)(得到信息)我們大多數(shù)采用“4”進行判斷。

2、readyState VS status 區(qū)別

通過對readyState 和 status的一系列操作,可以知道:

  • readyState:表明客戶端與客戶的交互狀態(tài)過程
  • status:體現(xiàn)的是服務器對請求的反饋,數(shù)據(jù)是否正常
  • load: 當狀態(tài)為4(等同于readyState===4),4為一種完成狀態(tài)(響應內(nèi)容解析完成狀態(tài)),觸發(fā)調(diào)用load事件

為此,我專門查了關(guān)于eadyState和status兩種ajax狀態(tài),找到這么一篇資料較為好理解,可以看看,原文戳:
AJAX 狀態(tài)值(readyState)與狀態(tài)碼(status)詳解

(1)AJAX狀態(tài)值(readyState)與狀態(tài)碼(status)區(qū)別
A、AJAX狀態(tài)值是指,
運行AJAX所經(jīng)歷過的幾種狀態(tài),無論訪問是否成功都將響應的步驟,可以理解成為AJAX運行步驟。如:正在發(fā)送,正在響應等,由AJAX對象與服務器交互時所得;使用“ajax.readyState”獲得。(由數(shù)字1~4單位數(shù)字組成)
B、AJAX狀態(tài)碼是指, 無論AJAX訪問是否成功,由HTTP協(xié)議根據(jù)所提交的信息,服務器所返回的HTTP頭信息代碼,該信息使用“ajax.status”所獲得;(由數(shù)字1XX,2XX三位數(shù)字組成,詳細查看RFC)
這就是我們在使用AJAX時為什么采用下面的方式判斷所獲得的信息是否正確的原因。

if(ajax.readyState == 4 && ajax.status == 200) { 
     putData(ajax.responseText);
}

(2) AJAX運行步驟與狀態(tài)值說明
在AJAX實際運行當中,對于訪問XMLHttpRequest(XHR)時并不是一次完成的,而是分別經(jīng)歷了多種狀態(tài)后取得的結(jié)果,對于這種狀態(tài)在AJAX中共有5種,分別是:
0 - (未初始化)還沒有調(diào)用send()方法
1 - (載入)已調(diào)用send()方法,正在發(fā)送請求
2 - (載入完成)send()方法執(zhí)行完成,
3 - (交互)正在解析響應內(nèi)容
4 - (完成)響應內(nèi)容解析完成,可以在客戶端調(diào)用了
對于上面的狀態(tài),其中“0”狀態(tài)是在定義后自動具有的狀態(tài)值,而對于成功訪問的狀態(tài)(得到信息)我們大多數(shù)采用“4”進行判斷。

(3)AJAX狀態(tài)碼說明
1:請求收到,繼續(xù)處理
2
:操作成功收到,分析、接受
3:完成此請求必須進一步處理
4
:請求包含一個錯誤語法或不能完成
5**:服務器執(zhí)行一個完全有效請求失敗
100——客戶必須繼續(xù)發(fā)出請求
101——客戶要求服務器根據(jù)請求轉(zhuǎn)換HTTP協(xié)議版本
200——交易成功
201——提示知道新文件的URL
202——接受和處理、但處理未完成
203——返回信息不確定或不完整
204——請求收到,但返回信息為空
205——服務器完成了請求,用戶代理必須復位當前已經(jīng)瀏覽過的文件
206——服務器已經(jīng)完成了部分用戶的GET請求
300——請求的資源可在多處得到
301——刪除請求數(shù)據(jù)
302——在其他地址發(fā)現(xiàn)了請求數(shù)據(jù)
303——建議客戶訪問其他URL或訪問方式
304——客戶端已經(jīng)執(zhí)行了GET,但文件未變化
305——請求的資源必須從服務器指定的地址得到
306——前一版本HTTP中使用的代碼,現(xiàn)行版本中不再使用
307——申明請求的資源臨時性刪除
400——錯誤請求,如語法錯誤
401——請求授權(quán)失敗
402——保留有效ChargeTo頭響應
403——請求不允許
404——沒有發(fā)現(xiàn)文件、查詢或URl
405——用戶在Request-Line字段定義的方法不允許
406——根據(jù)用戶發(fā)送的Accept拖,請求資源不可訪問
407——類似401,用戶必須首先在代理服務器上得到授權(quán)
408——客戶端沒有在用戶指定的餓時間內(nèi)完成請求
409——對當前資源狀態(tài),請求不能完成
410——服務器上不再有此資源且無進一步的參考地址
411——服務器拒絕用戶定義的Content-Length屬性請求
412——一個或多個請求頭字段在當前請求中錯誤
413——請求的資源大于服務器允許的大小
414——請求的資源URL長于服務器允許的長度
415——請求資源不支持請求項目格式
416——請求中包含Range請求頭字段,在當前請求資源范圍內(nèi)沒有range指示值,請求也不包含If-Range請求頭字段
417——服務器不滿足請求Expect頭字段指定的期望值,如果是代理服務器,可能是下一級服務器不能滿足請求
500——服務器產(chǎn)生內(nèi)部錯誤
501——服務器不支持請求的函數(shù)
502——服務器暫時不可用,有時是為了防止發(fā)生系統(tǒng)過載
503——服務器過載或暫停維修
504——關(guān)口過載,服務器使用另一個關(guān)口或服務來響應用戶,等待時間設定值較長
505——服務器不支持或拒絕支請求頭中指定的HTTP版本

(4) AJAX運行步驟示義圖

image

3、繼續(xù)探究一下所請求的后端數(shù)據(jù)文件

在xhr.open()中要求請求服務器,即請求一個資源,而url則是定位一個資源
將所請求的服務器定位成請求一些資源,如'/hello.json'。假如模擬后端的數(shù)據(jù),比如請求一個登陸數(shù)據(jù):'/login',請求時帶有一些參數(shù),如將用戶所輸入的數(shù)據(jù)拼裝成類似url形式:
'/login?username=wangxiaoqin&password=12345'作為資源請求

4、通過post形式去請求數(shù)據(jù)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
   <body>
    <script>        
    var xhr = new XMLHttpRequest()
        xhr.open('POST','/1.json',true)
        xhr.send('username=wangxiaoqin&password=12345')//直接發(fā)送數(shù)據(jù)
        xhr.addEventListener('load',function(){
            console.log(xhr.status)
            if((xhr.status >= 200 && xhr.status <300) ||xhr.status ===304){
                var data = xhr.responseText
                console.log(data)

            }else{
                console.log('error')
            }           
        })
        </script>
   </body>
</html>

'username=wangxiaoqin&password=12345' 這段拼接的過程可以通過寫一個函數(shù)展現(xiàn):

//傳遞一個參數(shù):
makeUrl({
  username:'wangxiaoqin',
  password:12345
})
//拼接一個url,通過遍歷這個對象,進行拼接
function makeUrl(obj){
   var arr = []
   for(var key in obj){
       arr.push(key + '=' + obj[key])
     }
     return  arr.join('&')
   }

那么,xhr.send()便直接可以發(fā)送這個對象

xhr.send(makeUrl({
  username:'wangxiaoqin',
  password:12345
}))

四、ajax幾種寫法

1、第1種:

關(guān)鍵詞:

readyState === 4
onreadystatechange

var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://api.jirengu.com/weather.php', true)
xhr.onreadystatechange = function(){
    if(xhr.readyState === 4) {
        if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
            //成功了
            console.log(xhr.responseText)
        } else {
            console.log('服務器異常')
        }
    }
}
xhr.onerror = function(){
    console.log('服務器異常')
}
xhr.send()

2、第2種:

關(guān)鍵詞:
onload

var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://api.jirengu.com/weather.php', true)
xhr.onload = function(){
    if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
        //成功了
        console.log(xhr.responseText)
    } else {
        console.log('服務器異常')
    }
}
xhr.onerror = function(){
    console.log('服務器異常')
}
xhr.send()

3、第3種:封裝1個ajax

//封裝,調(diào)用ajax對象,傳遞一些固定參數(shù)
function ajax(opts){
    var url = opts.url
    var type = opts.type || 'GET'// ||或:前者undefined,默認后者
    var dataType = opts.dataType || 'json'
    var onsuccess = opts.onsuccess || function(){}
    var onerror = opts.onerror || function(){}
    var data = opts.data || {}
    
    //將上面用戶請求的數(shù)據(jù)對象進行處理,拼接一個url
    var dataStr = []
    for(var key in data){
        dataStr.push(key + '=' + data[key])
    }
    dataStr = dataStr.join('&')
    
    if(type === 'GET'){
        url += '?' + dataStr
    }
   
   //做一個ajax
    var xhr = new XMLHttpRequest()
    xhr.open(type, url, true)
    xhr.onload = function(){
        if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
            //成功了
            if(dataType === 'json'){
                onsuccess( JSON.parse(xhr.responseText))//返回的數(shù)據(jù)
            }else{
                onsuccess( xhr.responseText)
            }
        } else {
            onerror()
        }
    }
    xhr.onerror = onerror
    if(type === 'POST'){
        xhr.send(dataStr)
    }else{
        xhr.send()
    }
}

//ajax設置一些參數(shù)對象
ajax({
    url: 'http://api.jirengu.com/weather.php',
    data: {
        city: '北京'
    },
    onsuccess: function(ret){
        console.log(ret)
    },
    onerror: function(){
        console.log('服務器異常')
    }
})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容