Fetch API 심화 (Advanced Fetch API)
자바스크립트에서 네트워크 요청을 다룰 때 Fetch API는 강력하고 유연한 도구다. 단순한 GET 요청부터 복잡한 설정까지, 다양한 상황에 맞춰 활용할 수 있다. 이번에는 Fetch API의 기본을 넘어 심화된 활용법을 코드와 함께 자세히 풀어보려고 한다.
Fetch API를 깊이 이해하면 요청 처리와 응답 관리를 훨씬 효율적으로 할 수 있다. 단계별로 차근차근 알아보자.
Fetch API 기본 복습
fetch
는 Promise를 반환하며, 간단한 요청을 이렇게 처리할 수 있다:
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json())
.then((data) => console.log(data.title))
.catch((error) => console.log(error));
// "sunt aut facere repellat provident occaecati excepturi optio reprehenderit"
async/await
를 사용하면 더 깔끔해진다:
async function getPost() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
const data = await response.json();
console.log(data.title);
}
getPost();
// "sunt aut facere repellat provident occaecati excepturi optio reprehenderit"
이제 여기서 더 나아가 보자.
1. 요청 옵션 커스터마이징
fetch
는 두 번째 인자로 옵션 객체를 받아 요청을 세밀하게 조정할 수 있다:
async function createPost() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "새 글",
body: "내용입니다",
userId: 1
})
});
const data = await response.json();
console.log(data);
}
createPost();
// { id: 101, title: "새 글", body: "내용입니다", userId: 1 }
POST 요청에 헤더와 본문을 추가해서 데이터를 전송했다.
2. 응답 상태 확인과 에러 처리
fetch
는 404나 500 같은 오류 상태에서도 Promise를 거부하지 않으니, 상태를 직접 확인해야 한다:
async function fetchWithError(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP 오류: ${response.status}`);
}
return response.json();
}
async function run() {
try {
const data = await fetchWithError("https://jsonplaceholder.typicode.com/posts/999");
console.log(data);
} catch (error) {
console.log(error.message);
}
}
run();
// "HTTP 오류: 404"
response.ok
로 성공 여부를 확인하고, 실패 시 에러를 던졌다.
3. AbortController로 요청 중단
AbortController
를 사용하면 요청을 중간에 취소할 수 있다:
async function fetchWithAbort() {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 1000);
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts",
{ signal }
);
const data = await response.json();
console.log(data);
} catch (error) {
if (error.name === "AbortError") {
console.log("요청이 중단됨");
} else {
console.log(error.message);
}
}
}
fetchWithAbort();
// 1초 후 "요청이 중단됨"
1초 후 요청을 중단해서 불필요한 네트워크 작업을 막았다.
4. 스트림으로 응답 처리
Response.body
를 사용하면 데이터를 스트림으로 받아올 수 있다:
async function streamResponse() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const reader = response.body.getReader();
const decoder = new TextDecoder();
let result = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
result += decoder.decode(value);
}
const data = JSON.parse(result);
console.log(data[0].title);
}
streamResponse();
// "sunt aut facere repellat provident occaecati excepturi optio reprehenderit"
대용량 데이터를 조각 단위로 처리해서 메모리를 효율적으로 사용했다.
5. 파일 업로드 구현
FormData
를 활용해서 파일을 업로드할 수 있다:
async function uploadFile() {
const formData = new FormData();
const file = new File(["테스트 데이터"], "test.txt", {
type: "text/plain"
});
formData.append("file", file);
formData.append("userId", "1");
const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
body: formData
});
const data = await response.json();
console.log(data);
}
uploadFile();
// { id: 101, ... } (서버 반영은 모의 데이터로 처리됨)
FormData
로 파일과 추가 데이터를 함께 보냈다.
6. 캐싱과 요청 재사용
cache
옵션으로 캐싱 전략을 조정할 수 있다:
async function fetchWithCache() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts/1", {
cache: "force-cache" // 캐시 강제 사용
});
const data = await response.json();
console.log(data.title);
}
fetchWithCache();
// 캐시가 있으면 네트워크 요청 없이 캐시에서 가져옴
force-cache
로 캐시를 우선 사용하도록 설정했다.
7. 요청 재시도 로직 추가
실패 시 재시도하는 로직을 구현해보자:
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP 오류: ${response.status}`);
}
return response.json();
} catch (error) {
if (i === retries - 1) throw error;
console.log(`재시도 ${i + 1} 실패: ${error.message}`);
await new Promise((r) => setTimeout(r, 1000));
}
}
}
async function run() {
try {
const data = await fetchWithRetry("https://jsonplaceholder.typicode.com/posts/999");
console.log(data);
} catch (error) {
console.log("최종 실패: " + error.message);
}
}
run();
// "최종 실패: HTTP 오류: 404" (3번 재시도 후)
실패 시 1초 대기 후 최대 3번 재시도하도록 했다.
8. 성능과 안정성에 미치는 영향
Fetch API의 심화 활용이 코드에 어떤 영향을 주는지 살펴보자:
- 성능: 스트림 처리와 캐싱으로 대용량 데이터나 반복 요청을 최적화할 수 있다.
- 안정성: 에러 처리, 중단, 재시도로 네트워크 불안정성을 줄인다.
옵션 설정과 AbortController를 활용하면 요청 흐름을 완벽히 제어할 수 있다.
마무리
Fetch API는 단순한 요청을 넘어 스트림 처리, 파일 업로드, 재시도 등 다양한 상황에서 유연하게 동작한다. 옵션과 기능을 잘 조합하면 네트워크 작업을 안정적이고 효율적으로 관리할 수 있다.
'코딩 공부 > 자바스크립트' 카테고리의 다른 글
72. 자바스크립트 jQuery 기초 (jQuery Basics) (2) | 2025.03.24 |
---|---|
71. 자바스크립트 Canvas API (2) | 2025.03.24 |
69. 자바스크립트 히스토리 API (Browser History API) (3) | 2025.03.23 |
68. 자바스크립트 비동기 타임아웃 관리 (Managing Async Timeouts) (1) | 2025.03.23 |
67. 자바스크립트 async/await 최적화 (Optimizing Async/Await) (1) | 2025.03.22 |