Fetch API 與 HTTP 請求
Fetch — 瀏覽器內建的 HTTP 客戶端
// 最簡單的 GET 請求
let response = await fetch("https://api.example.com/users");
let data = await response.json(); // ← 解析 JSON 回應
console.log(data);
GET 請求
async function getUsers() {
try {
let response = await fetch("/api/users");
// 檢查 HTTP 狀態
if (!response.ok) { // ← ok = 200-299
throw new Error(`HTTP ${response.status}`);
}
let users = await response.json(); // ← 解析 JSON
return users;
} catch (error) {
console.error("取得使用者失敗:", error);
}
}
// 帶查詢參數
let params = new URLSearchParams({
page: 1,
limit: 10,
search: "小明"
});
let response = await fetch(`/api/users?${params}`);
// URL: /api/users?page=1&limit=10&search=小明
POST 請求
async function createUser(userData) {
let response = await fetch("/api/users", {
method: "POST", // ← HTTP 方法
headers: {
"Content-Type": "application/json", // ← 告訴伺服器是 JSON
},
body: JSON.stringify(userData), // ← 把物件轉成 JSON 字串
});
if (!response.ok) {
let error = await response.json();
throw new Error(error.message);
}
return await response.json();
}
// 使用
let newUser = await createUser({
name: "小明",
age: 20,
email: "ming@test.com"
});
PUT / DELETE
// PUT — 更新資料
async function updateUser(id, data) {
return await fetch(`/api/users/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
}
// DELETE — 刪除資料
async function deleteUser(id) {
return await fetch(`/api/users/${id}`, {
method: "DELETE"
});
}
上傳檔案
async function uploadFile(file) {
let formData = new FormData(); // ← 用 FormData 包裝
formData.append("file", file); // ← 加入檔案
formData.append("name", "my-file"); // ← 加入其他欄位
let response = await fetch("/api/upload", {
method: "POST",
body: formData // ← 不需要設 Content-Type
// 瀏覽器會自動設定 multipart/form-data
});
return await response.json();
}
// 搭配 <input type="file">
let fileInput = document.querySelector("#fileInput");
fileInput.addEventListener("change", async (e) => {
let file = e.target.files[0]; // ← 取得選中的檔案
await uploadFile(file);
});
錯誤處理模式
// 封裝成通用 API 函式
async function apiRequest(url, options = {}) {
let defaultOptions = {
headers: { "Content-Type": "application/json" },
...options
};
if (options.body && typeof options.body === "object") {
defaultOptions.body = JSON.stringify(options.body);
}
let response = await fetch(url, defaultOptions);
if (!response.ok) {
let errorBody;
try {
errorBody = await response.json();
} catch {
errorBody = { message: response.statusText };
}
throw {
status: response.status,
message: errorBody.message || "未知錯誤",
data: errorBody
};
}
// 204 No Content
if (response.status === 204) return null;
return await response.json();
}
// 使用
try {
let users = await apiRequest("/api/users");
let newUser = await apiRequest("/api/users", {
method: "POST",
body: { name: "小明", age: 20 }
});
} catch (err) {
if (err.status === 401) {
// 導向登入頁
} else if (err.status === 404) {
// 顯示找不到
} else {
// 通用錯誤處理
alert(err.message);
}
}