認識 Ajax

發請求有哪幾種方式:

比較常規來講解

  • form 表單來發起 get 或 post 請求,但會刷新頁面
  • a 標籤可以發 get 請求,但會刷新頁面
  • img 標籤可以發 get 請求,但只能以圖片形式來展示
  • link 標籤可以發 get 請求,但只能以 css 和 favicon 等形式來展示
  • script 標籤可以發 get 請求,但只能以腳本形式來執行

如果用 CRUD 的形式來實現:

  • get
  • post
  • put
  • delete

在 http 裡,response 是字串

重新認識 Ajax

Ajax 是 Asynchronous JavaScript and XML (異步 JavaScript 和 XML)

Ajax 可以通過 JavaScript 來異步通訊 (client 和 Server 進行通訊)。Ajax 可以在不用刷新整個網頁,可以達到網頁局部更新。也就是說 client 向 server 請求獲取數據來進行網頁上更新,這樣提升用戶體驗。

傳統請求過程

  1. client 會向 server 發起 request
  2. server 會收到請求後,進行處理您要的東西
  3. 處理完後,server 將會創建 response
  4. 然後 server 將 response 給 client
  5. client 收到 response 後
  6. client 刷新整個頁面來更新數據

根據上面傳統請求過程步驟,我們可以知道這是同步行為。Ajax 可以讓 browser/client 和 server 之間異步通訊。我們可以通過 JavaScript 來發起請求來向 server 獲取數據來操作網頁內容局部更新,無需重刷新整個頁面,帶來用戶體驗效果!

Ajax 優點和缺點

優點

  • 減少 bandwidth,減輕 server 負擔, 減少請求,按照需要數據進行請求
  • 提高用戶體驗
  • …

缺點:

  • 對 SEO 不友善
  • debug 不友善
  • 不支持 browser back
    • 問題:ajax 可以做到無刷新,沒辦法更改 URL,所以 browser 不支持前進和後退。以分頁作為例子,當我順序點分頁123,URL 完全沒有變更 (局部請求資源)。我目前在分頁3,可是我點擊後退 (上一頁),照理來說後退回到分頁2,但我只回到最初上一個網址的內容分頁1,而不是分頁2。因為 ajax 不能在 browser 保留歷史紀錄。link
    • 解決之一:通過 HTML5 API history.pushState 或 history.replaceState 來操作 browser 歷史紀錄和無刷新行為來改變 URL。
  • 安全性問題
  • …

Ajax 與跨域

只有在同源策略情況下允許發 ajax 請求。
在非同源情況下,使用 ajax 發送請求,由於 ajax 可以讀取 response 內容,所以 browser 認為是不安全,可以發送,但 browser 不會給你響應 (會被擋)。

例子:

  1. https://facebook.com 可以向 https://www.facebook.com 發 ajax 請求嗎?
    答案:不行

如果我想透過 ajax 跨域呢?
本來 A網站想請求 B網站內容,但他們是不同域,造成無法請求響應。
可以用 cors 來告訴 browser (A網站)和(B網站)是朋友,A網站要 B網站內容,給他吧。

只要在後端 response header 設定 Access-Control-Allow-origin, 指定允許 A網站。
如果是多個不同域可以這樣設定 Access-Control-Allow-origin, *。

跨域

browser 限制下不允許透過 JS 跨域,所以 ajax 是不被允許。像 browser 本身是沒有限制自己,如 form, img, script, link, a 等標籤都可以允許與 server 通訊,可以被說成跨域行為。

例子1: form 表單提交到另一個網站後,原本頁面無法取得新頁面內容,所以 browser 是認為安全。

例子2: script 標籤裡,我們可以請求任意不同 domain。我們也知道在同源策略裡只要 (協議,域名,端口) 三個不同就是跨域行為。

在回顧跨域和同源策略是什麼,強逼自己記在心裡。

  • 同源策略 - 協議,域名,端口 必須相同
  • 跨域 - 協議,域名,端口 不相同等同於跨域行為

關於更多 CORS 請到 link

總結

雖然 ajax 真的很方便也非常安全,因為有同源策略 (Same origin policy),只有協議,域名,端口 必須相同。如果非要通過 ajax 來跨域的話,需要後端開啟允許可跨域來告訴 browser 我們是朋友。browser 會根據 response header 裡字段 Access-Control-Allow-Origin 知道你們關係。

實戰 code


面試題

  1. 請使用原生 JS 來發送 ajax 請求
    答:

    let request = new XMLHttpRequest()
    request.open('GET', 'https://jsonplaceholder.typicode.com/todos') // 配置
    request.onreadystatechange = function () {
    if (request.readyState === 4) {
     console.log('請求response完成')
     if (request.status >= 200) {
       console.log('請求成功')
       let string = request.responseText
       let data = JSON.parse(string)
       console.log(data)
     } else if (request.status >= 400) {
       console.log('請求失敗')
     }
    }
    }
    request.send()
    
  2. JSON 和 JavaScript
    答: JSON 不具備程式語言特性,它是數據傳輸格式。 JSON 官方

JSON 和 XML 都是數據格式,相比之下 JSON 可讀性很高,也得到大眾的使用!

-------------------------------------------
   JS              VS         JSON
-------------------------------------------
undefined                     沒有
null                          null
boolean                      boolean
function f1(){...}            沒有
{name: 'decadehew'}        {"name":"decadehew"}
['a', 'b']                 ["a", "b"]
'decadehew'                  "decadehew"
let person = {}               沒有







// ---------------------
// JS convert to JSON
// ---------------------
JSON.stringify({name: 'decadehew'}) // {"name": "decadehew"}

// -----------------------------
// JSON String convert to JS 
// 符合 JSON 字串來表示 JS 的值
// -----------------------------

稍微說明:
// '"foo"' 是 JSON 字串,
// parse 會解析 JSON 字串轉換成 JS 的值(字串)。
// 你可以看符合 JSON 字串裡所表示/描述是什麼,它就是 JS 某類型的值!
// 
// 
// '"foo"' 表示是 JS 字串類型,
// "true" 表示是 boolean 類型,
// {} 表示是 JS 對象類型。
JSON.parse('"foo"') // 'foo'
JSON.parse('true'); // true
JSON.parse({"name": "decadehew"}) // {name: 'decadehew'}

參考