5分鐘回顧原生ajax的幾個知識點

今天早上在整理筆記的時候,發現了很久之前的有關ajax的相關內容.當時主要用的還是jQuery$.ajax().現在jQuery也快要退出歷史舞臺了,所以今天我們就來講講原生的ajax吧.

基本用法

首先簡單的介紹一下ajax,全稱是Asynchronous JavaScript + XML(異步JavaScript和XML).這不是一個語言,也不是一種新技術,只是一個在2005年被提出來的新術語,其類似的技術手段最早可以追溯到上個世紀末,而最早大規模使用ajax技術的是Gmail.大家都知道,以前的網頁提交數據是通過form表單提交的,一提交就要全局刷新,煩得很.雖然後來可以用iframe的方式解決這個問題,但總歸是太繁瑣了.而ajax則是解決了這個痛點,它通過XMLHttpRequest對象向服務器發送異步請求,獲得返回的數據後,再操作DOM來將增量更新呈現在用戶界面上,做到無痛刷新.

下面我們來看這段代碼,這是一個發送get請求的代碼示例,相信大家應該都比較熟悉了吧!其實這還是一個縮減版的代碼,在紅寶書第3版中,爲了所謂的瀏覽器兼容性,它還多了一步,即選擇ActiveXObject對象中的傳入值(我們現在傳入的是Microsoft.XMLHTTP,其實還有其他的選項).這個太遙遠了,現在來看也沒有啥太大意義,只是感概一下以前的老程序員不容易啊.瀏覽器之間神仙打架,程序員之間凡人遭殃.

function ajax(method, url, async = true){
  let xhr = null
  if(window.ActiveXObject){  // IE5 IE6纔有這個對象,是微軟獨有的,現在基本也沒有這倆瀏覽器了,可以不用管了
    xhr = new ActiveXObject('Microsoft.XMLHTTP')
  }else if(window.XMLHttpRequest){  // 現代瀏覽器基本都有這個
    xhr = new XMLHttpRequest()  // 實例化一個XMLHttpRequest
  }
  xhr.open(method ,url, async)  // 啓動階段,請求還沒有發送
  xhr.onreadystatechange = function(){  // 監聽readyState狀態變化
    if(xhr.readyState === 4){
      if(xhr.status === 200){
        console.log(xhr.responseText)
      }
    }
  }
  xhr.send(null)  // 發送階段
}
ajax('get','http://jsonplaceholder.typicode.com/posts/1')

這裏我們的請求鏈接是http://jsonplaceholder.typicode.com/posts/1,這是一個假數據在線接口(Fake Online REST API).這裏給大家安利一個在線工具,jsonplaceholder,它上面有很多的接口,允許我們跨域訪問獲取一些假數據.這個對於我們平時測試啥的也挺方便的.它也支持多種請求方式,除了最基本的GETPOST,其他的像什麼PUT,PATCH等也都是支持的.

open方法有三個參數,第一個參數表示請求方式,第二個參數表示請求的url,一般我們請求自己所屬域的時候,寫相對路徑即可,在請求訪問遠程鏈接的時候才寫絕對路徑.第三個參數就是是否異步,一般都是異步.這裏提一點,get請求也是可以帶參數的,叫做queryString,它是一個拼接在url中的字符串.如 https://www.xxx.com?name=zhangsan&age=12 這個url中,name=zhangsan&age=12就是這個請求帶過去的參數.通過key=value的形式表示鍵值對,每個鍵值對之間通過&符號連接,第一個鍵值對之前則有一個?.這裏還要介紹另外一個方法: encodeURIComponent() 這是一個對URI的組成部分進行編碼的方法.因爲在有效的URL中是不能包含某些字符的,比如像空格之類的.這時我們就可以用這個方法對空格進行轉義,會變成%20.我們來看下面例子:

let str = 'https://www.xxx.com?name=狗子'
let str2 = `https://www.xxx.com?${encodeURIComponent('name')}=${encodeURIComponent('狗子')}`
console.log(str2)  // https://www.xxx.com?name=%E7%8B%97%E5%AD%90

可以看到狗子這兩個漢字已經被轉義了.

onreadystatechange方法是監聽readyState的變化,至於readyState是什麼,我們下面會稍微介紹下的.

send方法調用了以後,請求才是被真正的發送出去.此方法裏面的參數表示要發送的數據,沒有的話我們也要填寫null,不然在某些瀏覽器中可能會報錯.下面我們來發送一個post請求

function ajax(method, url, async = true){
  const xhr = new XMLHttpRequest() 
  const data = {
    title:'title1',
    body:'body1',
    userId:1
  }
  xhr.open(method ,url, async) 
  xhr.setRequestHeader('Content-Type','application/json;charset=utf-8')  // 設置個請求頭唄
  xhr.onreadystatechange = function(){  // 監聽readyState狀態變化
    if(xhr.readyState === 4){
      console.log(xhr.responseText) 
    }
  }
  xhr.send(JSON.stringify(data))
}
ajax('post','http://jsonplaceholder.typicode.com/posts')

這裏post請求爲啥要設置一個請求頭? 說實話,我也不是特別清楚,感覺應該和服務器的設置有關.我去查了相關資料,覺得下面的說法最靠譜吧. 因爲不加這個,服務器很有可能無法獲取到我們發送的信息.我們設置此內容可以確保服務器知道實體中有參數.

readyState狀態值

這個表示的是ajax請求的狀態值,即一個ajax所要經歷的幾個階段,無論訪問是否成功都將響應.大家可以在上面ajax函數的onreadystatechange事件中打印readyState,並將請求鏈接隨便改成一個不存在的地址既可證明.

  • 0 表示請求未初始化 剛開始就是這個狀態,還未調用open()方法
  • 1 啓動 此時已經調用了open()方法
  • 2 發送 此時已經調用了send()方法
  • 3 請求接收中 此時已經接受了一部分數據
  • 4 請求完成 數據接受完畢

這幾個狀態大家瞭解一下就行了,不必強行記憶.我們主要關心的狀態4,就是此時響應體已經下載完畢,我們可以獲取響應體的內容了.通過xhr.responseText來獲取,responseText獲取的是字符串形式的響應數據.另外還有一個responseXML獲取的是XML形式的響應數據,我就沒用到過,不去管了 (PS: 雖然感覺沒有記住全部狀態碼的必要,但我以前在學的時候,還是順帶着記憶了一下.我是把發送請求比作是發射火箭的過程,0就是發射前準備階段,1就是把火箭推出來了,但還沒有發射.2就是按下發射按鈕,火箭接收到發射命令,起飛了.這裏ajax中的調用方法也是send,很形象.3就是火箭升空後返回一些數據的過程,比如高度,速度,燃料情況等,4就是火箭已經進入太空,該返回的數據都返回了,一切正常,大家可以暫時放鬆一下了.就好像火箭發射,肯定會經歷這幾個階段,ajax也一樣,都會經歷上面的階段.)

HTTP狀態碼

http狀態碼大家應該都比較熟悉了.像我們最常見的200,表示請求成功了,304表示使用緩存,404表示請求資源不存在以及500一般表示服務器錯誤等.http狀態碼有很多,但我們平時使用的估計也就10種不到吧.通常我們可以歸納爲如下:

  • 1xx 信息響應類
  • 2xx 處理成功響應
  • 3xx 重定向
  • 4xx 客戶端錯誤
  • 5xx 服務器錯誤

具體所有的細節,大家可以在這裏看到.

load事件

Firefox最早引入的一個事件,用來代替readystatechange,因爲此時的readyState已經變成4了.

xhr.onload = function(){
  console.log(xhr.readyState)  // 4
  if(xhr.status === 200){
    console.log(xhr.responseText)
  }
}

除了load事件以外,XMLHttpRequest 2級中還實現了很多其他事件.具體可以參考MDN.

CORS(跨域資源共享)

全稱是Cros-Origin Resource Sharing,跨域資源共享.因爲瀏覽器的同源策略,同源策略中的其中一種即是XMLHttpRequest同源策略,它禁止使用XHR對象向不同源的服務器地址發起HTTP請求.一般情況下,只能訪問同源的資源,同源指的是協議(protocol),域名(host),端口(port)等都相同.

對於CORS的介紹,紅寶書中是這麼說的.它是一個W3C標準,定義了在必須訪問跨域資源時,瀏覽器和服務器之間應該如何溝通.其背後基本思想,就是使用自定義的 HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,還是應該失敗.

傳統的跨域請求的解決方案基本就是JSONPiframe.而現在要允許跨域訪問,一般我們需要設置Access-Control-Allow-Origin,這是HTML5中定義的一種解決資源跨域的策略.需要瀏覽器和服務器同時支持.比如 Access-Control-Allow-Origin:*,這裏的*表示所有域都能訪問,如果只允許某個特定域訪問的話,則設置如下:Access-Control-Allow-Origin:http://www.xxx.com,表示只有http://www.xxx.com這個網址下的可以正常訪問該服務器,對於其他沒有該標識的域則會提示禁止訪問.當服務器返回的資源中加入了Access-Control-Allow-Origin頭標識後,瀏覽器才允許跨域訪問.我們來看下jsonplaceholder返回的響應頭信息
response_header
當然還有一種解決跨域問題的方案就是使用代理服務器,現在我們公司項目都是前後端分離的,在vue項目中,基本都自帶了http服務器.在配置項中的proxyTable中進行設置即可.

總結

其實現在基本不太會有人還在項目中使用原生ajax了.大部分人用的應該還是jQuery或者Axios等.我們今天講原生ajax,主要還是爲了鞏固下相關知識點.我上面講的東西,相信大家當初應該都學過,只是時間久了可能會忘,所以今天我們只是回顧下.所謂溫故而知新,可以爲師矣.在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章