National Chengchi University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

政治大學 AQI 58 25°C PM2.5 12
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 26

AJAX:XMLHttpRequest 與 fetch

不重新整理頁面就更新內容
Interaction 25 minute(s)

Learning Objectives

  • 說明 AJAX 如何不重新整理頁面就與伺服器交換資料,以及它的優缺點
  • 認識 HTTP 請求方法(GET、POST)、狀態碼、API 與 JSON 在 AJAX 裡的角色
  • 說明 XMLHttpRequest 的流程:建立物件、open、send、在 onload 讀取 responseText
  • 用 fetch 搭配 then 或 async/await 取得資料,檢查 response.ok 與 status,並送出 POST 請求

AJAX:不重新整理頁面就更新內容

傳統的網頁每做一件事就要換一整頁:送出表單 → 伺服器處理 → 送回一整個新網頁。 前後兩頁大部分的 HTML 都一樣(頁首、選單、頁尾),還是要重新傳一次,浪費頻寬,畫面也會閃一下。

AJAX(Asynchronous JavaScript and XML,非同步 JavaScript 與 XML)的做法不同:

  1. 使用者操作(例如按「載入更多」)
  2. JavaScript 在背景向伺服器送出請求,頁面不動
  3. 伺服器只回傳需要的資料(現在大多是 JSON)
  4. JavaScript 收到資料,只更新頁面上需要改變的那一塊

AJAX 不是一種新的語言,而是一組技術的組合;這個名稱由 Jesse James Garrett 在 2005 年提出。名稱裡雖然有 XML,現在傳的資料以 JSON 為主,也可以是純文字或 HTML。 社群網站往下捲就自動載入新貼文、搜尋框邊打字邊出現建議,都是 AJAX。

優點 要注意的地方
只傳必要的資料,回應更快、伺服器負擔較小 用 AJAX 換掉的內容不會自動進入瀏覽器歷史,「上一頁」與書籤可能回不到剛剛的狀態
頁面不會整個重新載入,操作比較流暢 網路有延遲,要顯示「載入中…」並處理失敗的情況,否則使用者以為壞掉了
不需要安裝外掛,瀏覽器內建 需要瀏覽器允許執行 JavaScript

HTTP 請求、狀態碼、API 與 JSON

瀏覽器與伺服器之間用 HTTP 溝通:瀏覽器送出請求(request),伺服器回一個回應(response)。

請求方法:最常用的兩種

方法 用途 資料放在哪裡
GET 取得資料 網址的 query string,例如 http://www.example.com/?name=JavaScript
POST 送出、新增資料 請求的本文(body),網址上看不到

狀態碼:回應裡的三位數字,告訴你結果如何

狀態碼 意思
200 OK 成功
201 Created 成功新增了資料(常見於 POST)
404 Not Found 找不到這個網址
500 Internal Server Error 伺服器端出錯

API(Application Programming Interface,應用程式介面)是伺服器對外約定好的取得資料方式:哪個網址、用哪個方法、要帶什麼參數、會回傳什麼格式。 例如 GET /api/users 回傳使用者清單。前端只要照著約定送請求,不需要知道伺服器裡面怎麼做。

回傳的資料通常是 JSON 字串,用 JSON.parse()(或 fetch 的 response.json())轉成 JavaScript 的物件或陣列。

跨來源:網頁預設只能用 AJAX 讀取同一個來源(通訊協定+網域+連接埠都相同)的資料;要讀別的網站的 API, 那個網站必須在回應裡表明允許(這個機制叫 CORS,Cross-Origin Resource Sharing)。這也是上一課要開本機伺服器的原因之一。

本課的逐步執行動畫與網頁沙箱都沒有真的連上網路:/api/… 的回應是課程事先準備的假資料,所以每次的結果都一樣。

XMLHttpRequest:最早的 AJAX 寫法

XMLHttpRequest(常簡稱 XHR)是瀏覽器最早提供的 AJAX 工具。雖然名字有 XML 與 HTTP,它可以接收任何格式的資料。流程有四步:

const xhr = new XMLHttpRequest();        // 1. 建立物件
xhr.open('GET', '/api/news');            // 2. 設定方法與網址(第三個參數 true 表示非同步,預設就是 true)
xhr.onload = function () {               // 3. 設定收到回應時要做什麼
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
  }
};
xhr.send();                              // 4. 送出(POST 時把資料放在 send 的參數)

readyState 屬性記錄請求進行到哪裡,每次改變都會觸發 readystatechange 事件:

readyState 名稱 意思
0 UNSENT 物件建立了,還沒呼叫 open
1 OPENED 已經呼叫 open
2 HEADERS_RECEIVED 已經呼叫 send,收到回應的標頭
3 LOADING 正在接收回應的內容
4 DONE 完成,回應已經全部收到

舊的教材常寫 xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { … } },意思和 onload 相同。 很舊的 IE5、IE6 要用 new ActiveXObject("Microsoft.XMLHTTP"),現在的瀏覽器都不需要了。

XMLHttpRequest 的四個步驟

注意第 14 行先印出「請求已送出」:send() 不會等回應。300 ms 後回應到了,onload 才被呼叫。動畫裡的 xhr 是課程用的模擬版本,會多出 _h、_url 等內部欄位,readyState 也直接從 1 跳到 4;真正的瀏覽器會經過 2、3。

fetch:用 Promise 送出請求

fetch 是現在的標準寫法,回傳 Promise,所以可以用 then 或 await。取得資料要經過兩個階段:

fetch(url, options)             // 第一階段:Promise 完成時得到 Response 物件(只有狀態碼與標頭)
  .then((response) => response.json())   // 第二階段:讀取並解析內容,又是一個 Promise
  .then((data) => { … });
Response 的屬性與方法 意思
response.status 狀態碼,例如 200、404
response.ok 狀態碼在 200~299 之間時是 true
response.json() 把內容解析成物件或陣列(回傳 Promise)
response.text() 把內容當成字串(回傳 Promise)

最容易誤會的一點:fetch 只有在網路層失敗(斷線、網址連不上、被 CORS 擋下)時才會 rejected,錯誤是 TypeError: Failed to fetch。 伺服器回 404 或 500 時,Promise 仍然是 fulfilled,只是 response.ok 是 false。所以要自己檢查 response.ok,必要時自己 throw。

fetch+then:兩個階段

看第 3 行的 response:它不是資料本身,而是一個有 status、ok、json 的物件。要等第 5 行的 response.json() 完成,第 7 行才拿到真正的陣列 users。(動畫裡的 Response 是課程模擬的,顯示成一般物件。)

fetch+async/await,並檢查 response.ok

getJSON 是很常見的寫法:fetch 之後先檢查 response.ok,不是 2xx 就自己丟出錯誤。第二次請求 /api/users/99 得到 404:fetch 本身沒有失敗,是第 5 行的 throw 讓程式跳到 catch。

送出 POST 請求

fetch 的第二個參數是設定物件,送出資料時最常用這三項:

選項 意思
method 請求方法,預設 'GET';新增資料用 'POST'
headers 請求標頭;送 JSON 時要寫 {'Content-Type': 'application/json'},告訴伺服器內容的格式
body 要送出的內容;物件要先用 JSON.stringify() 轉成字串

伺服器處理完通常會回傳新增的那筆資料(例如加上了 id),並以 201 Created 回應。

用 POST 新增一位使用者

第 3 到 7 行是一個 fetch 呼叫:設定物件裡有 method、headers 與 body。這裡的假伺服器不會真的讀取 body,只會回傳事先準備好的回應 {id: 4, name: 'Dora'}。

想一想:XMLHttpRequest 與 fetch

1.

用 fetch('/api/missing') 請求一個不存在的網址,伺服器回應 404。fetch 回傳的 Promise 會怎樣?

2.

假設 /api/score 回傳 {"name": "Amy", "score": 92},下面的程式會印出什麼?

fetch('/api/score')
  .then((res) => res.json())
  .then((data) => console.log(data.name, data.score));
3.

XMLHttpRequest 的 readyState 是 4 代表什麼?

第 1 次作答

互動練習:按按鈕載入同學名單

範例已經在按下「載入名單」時送出 fetch('/api/users'),並在主控台印出狀態碼。依任務修改 JavaScript,按「執行」,再到右邊的預覽按按鈕測試。主控台會顯示 → GET /api/…,代表送出了一個請求;沙箱只會回應 /api/users 與 /api/missing 兩個網址(都是假資料)。

想一想:AJAX 的應用

1.

假設 /api/ping 會正常回應,下面的程式會印出什麼?

let msg = '開始';
fetch('/api/ping').then(() => {
  msg = '完成';
});
console.log(msg);
2.

要用 fetch 把 {name: 'Dora'} 以 JSON 格式 POST 給伺服器,body 應該怎麼寫?

3.

在 catch 裡收到 TypeError: Failed to fetch,最可能的原因是什麼?

第 1 次作答

重點精華回顧

  • AJAX 讓 JavaScript 在背景與伺服器交換資料,只更新頁面上需要改變的部分,不必重新載入整頁;要記得顯示載入中、處理失敗。
  • GET 取得資料(參數在 query string),POST 送出資料(放在 body);狀態碼 200 成功、201 新增成功、404 找不到、500 伺服器錯誤。
  • API 是伺服器約定好的取得資料方式,回傳的資料多半是 JSON;讀取其他網站的資料需要對方以 CORS 允許。
  • XMLHttpRequest:new XMLHttpRequest() → open(method, url) → 設定 onload → send();readyState 4 表示完成,內容在 responseText。
  • fetch 回傳 Promise,分兩階段:先得到 Response,再用 response.json() 取得資料;搭配 async/await 最好讀。
  • fetch 只在網路層失敗時 rejected;404、500 時要自己檢查 response.ok 或 response.status。
  • POST 時設定 method、headers(Content-Type: application/json)與 body: JSON.stringify(資料)。
這一課完成了!
Next lesson:物件導向:prototype
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。