認識 Ajax

發請求有哪幾種方式:

比較常規來講解

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

如果用 CRUD 的形式來實現:

  • get
  • post
  • put
  • delete

http 裡,response 是字串

重新認識 Ajax

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

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

傳統請求過程

  1. client 會向 server 發起 request
  2. server 會收到請求後,進行處理您要的東西
  3. 處理完後,server 將會創建 response
  4. 然後 serverresponseclient
  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.pushStatehistory.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'}

參考