Fetch API는 프로미스 기반 구문으로 HTTP 요청을 단순화하여 코드를 더 깔끔하고 사용하기 쉽게 만드는 현대적인 자바스크립트 인터페이스입니다. Fetch API를 사용하면 전체 페이지를 다시 로드하지 않고도 서버에서 데이터를 요청할 수 있어 애플리케이션이 더 빠르고 상호작용성이 높아집니다. 다양한 API와 상호작용하기 위해 GET, POST, PUT 또는 DELETE 요청을 쉽게 보낼 수 있습니다. Fetch API는 다양한 유형의 데이터와 HTTP 메서드 처리도 간편하게 만들어 줍니다. 요청 헤더를 맞춤 설정하고 다양한 콘텐츠 유형을 관리하는 것도 간단해져 다양한 서비스와 원활하게 작업할 수 있습니다.
이 글에서는 Fetch API 사용법, 웹 애플리케이션에 대한 이점, 안전하고 효율적인 데이터 처리를 위한 프록시 활용법을 배울 수 있습니다. 최고의 프록시 제공업체 목록을 살펴보고 Bright Data가 최상의 선택인 이유를 확인해 보세요.
Fetch API 이해하기
Fetch API는 서버에 요청을 전송하고 응답 데이터가 사용 가능해지면 이를 해결하는 Promise를 반환함으로써 비동기 HTTP 요청을 수행하는 데 사용됩니다. 자바스크립트 개발에서 Fetch API를 사용하면 애플리케이션이 페이지 재로딩 없이 서버와 통신할 수 있도록 하여 HTTP 요청(예: GET, POST, PUT)을 통한 서버와의 동적 상호작용을 가능하게 합니다. Fetch API의 장점은 다음과 같습니다:
- XMLHttpRequest
- 다양한 데이터 형식 지원: JSON, 텍스트, 블롭(blob) 형식을 사용할 수 있어 다양한 응답 유형을 쉽게 파싱하고 처리할 수 있습니다.
- 스트림 및 응답 객체 제공: 읽기 가능한 스트림으로 응답을 검사하고 수정할 수 있으며, 애플리케이션에 맞게 데이터 검색 방식을 조정할 수 있습니다.
- 향상된 오류 처리: Fetch는 기본적으로 HTTP 오류 상태 코드에 대해 오류를 발생시키지 않지만, 보다 명시적인 응답 검사를 수행할 수 있도록 합니다.
- 콜백 구조 간소화: 복잡한 콜백 코드 작성 대신
.then(),.catch()또는async/await를활용하여 요청 완료 시점을 알 수 있습니다.
Fetch API 사용의 이점을 살펴보았으니, 이제 주요 기능과 역량을 살펴보겠습니다.
비동기 작업
Fetch API는 비동기적이며, 서버 응답이 준비되면 프로미스가 해결됩니다. 이를 통해 사용자의 UI를 차단하지 않고 원활한 사용자 경험을 제공할 수 있습니다. 몇 가지 예시를 살펴보겠습니다.
GET 요청
Fetch API를 사용하여 GET 요청을 보내는 예시는 다음과 같습니다:
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
return response.json();
})
.then((data) => {
console.log('데이터 가져옴:', data);
})
.catch((error) => {
console.error('Fetch 오류:', error);
});
이 코드 조각에서는 Fetch API를 사용하여 jsonplaceholder.typicode.com에서 게시글을 가져옵니다. response.ok를 사용하여 응답이 정상인지 확인하고, 그렇지 않으면 에러를 발생시킵니다. 그런 다음 response.json()을 사용하여 응답을 JSON으로 파싱합니다. 네트워크 문제, 잘못된 형식의 응답, 파싱 실패 등 모든 에러는 .catch() 블록에서 처리됩니다.
POST 요청
Fetch API를 사용하여 POST 요청을 보내는 방법은 다음과 같습니다:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
body: JSON.stringify({
title: 'New Post',
body: 'Hello World! This is a test.',
userId: 1,
}),
})
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
return response.json();
})
.then((data) => {
console.log('새 게시물 생성됨:', data);
})
.catch((error) => {
console.error('Fetch 오류:', error);
});
여기서 Fetch API는 POST 메서드로 새 리소스를 생성하기 위한 요청을 보냅니다. POST 요청은 GET 요청과 유사하지만, API가 JSON 데이터를 전송한다는 사실을 서버에 알리기 위한 헤더가 포함됩니다. 실제 JSON 데이터는 body 키에 포함됩니다.
API와의 통합
Fetch API를 사용하여 공개 또는 비공개 API에 요청을 보낼 수 있습니다. 예를 들어 차트, 대시보드 또는 기타 데이터 기반 기능을 위한 데이터를 가져오는 데 사용할 수 있습니다. 이 API는 요청과 응답 처리를 위한 Promise 기반 흐름을 사용하여 웹 애플리케이션이 외부 서비스와 통신할 수 있도록 합니다.
OpenWeatherMap API에서 날씨 데이터를 가져오는 기본 예시는 다음과 같습니다:
const city = "London,uk";
const apiKey = "YOUR_API_KEY";
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${apiKey}`;
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
return response.json();
})
.then((weatherData) => {
console.log("런던 날씨 데이터:", weatherData);
})
.catch((error) => {
console.error("날씨 데이터 가져오기 중 오류:", error);
});
YOUR_API_KEY를실제 API 키로 교체하세요.
이 코드는 OpenWeather API를 사용하여 런던의 날씨 데이터를 가져옵니다. weatherData 객체에는 온도, 습도, 상태 등의 세부 정보가 포함되어 있으며, 이를 UI에 통합할 수 있습니다.
터미널이나 셸에서 이 코드를 실행하면(명령어: node filename.js) 다음과 같은 출력이 표시됩니다:
런던 날씨 데이터: {
coord: { lon: -0.1257, lat: 51.5085 },
weather: [
{
id: 804,
main: '구름',
description: '흐린 구름',
icon: '04d'
}
],
base: 'stations',
main: {
temp: 273.42,
feels_like: 273.42,
temp_min: 272.59,
temp_max: 274.87,
pressure: 1021,
humidity: 87,
sea_level: 1021,
grnd_level: 1016
},
visibility: 10000,
wind: { speed: 0.51, deg: 0 },
clouds: { all: 99 },
dt: 1736525048,
sys: {
type: 2,
id: 268730,
country: 'GB',
sunrise: 1736496173,
sunset: 1736525567
},
timezone: 0,
id: 2643743,
name: 'London',
cod: 200
}
앱은 외부 데이터를 가져오기 위해 종종 외부 API와 상호작용해야 합니다. 따라서 확장 가능한 웹 애플리케이션을 구축하는 데 있어 핵심은 모든 외부 서비스와 통합하기 위한 깔끔하고 일관된 접근 방식을 사용하는 것입니다.
오류 처리
네트워크 오류를 관리하기 위해 여러 이벤트 핸들러를 설정해야 했던 XMLHttpRequest 같은 구식 AJAX 방식과 비교해, Fetch는 Promise와 단일 .catch() 블록을 사용해 오류 처리를 단순화합니다. Fetch는 네트워크 오류(예: 인터넷 연결 없음)가 발생한 경우에만 Promise를 거부합니다. 404나 500 같은 HTTP 오류 코드에 대해서는 오류를 발생시키지 않습니다. 이러한 오류가 발생했는지 확인하려면 response.ok를 수동으로 확인해야 합니다. response. ok가 false라면 서버가 200~299 범위가 아닌 상태 코드로 응답했음을 의미합니다. 다음 예시는 잘못된 엔드포인트로 인해 요청이 실패했을 때 Fetch가 오류를 처리하는 방식을 보여줍니다:
fetch('https://jsonplaceholder.typicode.com/invalid-endpoint')
.then((response) => {
if (!response.ok) {
throw new Error(`Fetch 실패. 상태: ${response.status}`);
}
return response.json();
})
.then((data) => {
console.log('응답이 정상(ok)이 아닐 경우 이 코드는 실행되지 않습니다');
})
.catch((error) => {
console.error('네트워크 또는 응답 오류:', error.message);
});
이 코드를 실행하면 네트워크 또는 응답 오류: 가져오기 실패. 상태: 404라는 출력 메시지가 표시됩니다. 엔드포인트가 존재하지 않기 때문에 코드는 !response.ok를 확인하고 오류를 발생시킵니다.
Fetch API와 프록시 사용
프록시는 추가적인 보안, 확장성 및 지리적 위치 기능을 제공함으로써 Fetch API의 기능을 향상시킬 수 있습니다. 프록시는 클라이언트와 인터넷 사이의 중개자 역할을 하여 고유한 IP 주소, 추가적인 보안 계층 및 리소스 가져오기에 대한 보다 유연한 접근 방식을 제공합니다. Fetch와 함께 프록시를 사용하면 데이터 추출 또는 웹 스크래핑 활동 중 익명성을 제공함으로써 IP 주소가 차단되는 것을 방지하는 데 도움이 될 수 있습니다. 프록시 사용의 다른 이점은 다음과 같습니다:
- 보안 강화: 프록시는 IP 주소를 숨겨 악의적인 공격에 취약해질 위험을 줄입니다.
- 확장성: 프록시는 요청을 여러 IP에 분산시켜 속도 제한이나 차단 현상을 방지합니다.
- 지리적 위치 유연성: 프록시를 사용하면 다양한 위치에서 HTTP 요청을 전송할 수 있어 특정 지역에서만 이용 가능한 콘텐츠에 접근하는 데 유용합니다.
프록시의 유형
각기 다른 용도에 특화된 다양한 유형의 프록시가 존재합니다. 주요 프록시 유형은 다음과 같습니다:
- 주거용 프록시: 실제 주거 지역 IP를 사용하며 웹사이트로부터 높은 신뢰도를 얻습니다. 비용은 더 비싸지만 대상 웹사이트가 데이터센터 IP 트래픽을 차단하는 경우 효과적입니다.
- 회전 프록시: 요청이나 세션마다 IP를 자동으로 변경합니다. 서버 제한이나 블랙리스트에 걸릴 위험을 줄이면서 대규모 데이터 추출을 수행할 때 이상적입니다.
- 데이터센터 프록시: 데이터센터에서 제공되는 프록시로, 비용 효율적이고 고속이지만 빈번하게 사용할 경우 차단될 수 있습니다.
Bright Data 프록시와 Fetch API 통합
Bright Data는 Fetch 기반 애플리케이션과 통합되는 고급 프록시 서비스를 제공합니다. 이 프록시를 사용하면 주거용 또는 데이터센터 옵션 중에서 선택할 수 있으며, 기업 수준의 프로젝트를 위한 데이터 검색 능력을 확장하고 효율적이고 안정적인 데이터 수집을 위한 자동 IP 회전 기능을 활용할 수 있습니다.
Bright Data 프록시를 Fetch API와 통합하는 방법은 다음과 같습니다:
import fetch from "node-fetch";
import { HttpsProxyAgent } from "https-proxy-agent";
const proxyHost = "BRIGHT_DATA_PROXY_HOST:PORT";
const proxyUsername = "BRIGHT_DATA_USERNAME";
const proxyPassword = "BRIGHT_DATA_PASSWORD";
const proxyUrl = `http://${proxyUsername}:${proxyPassword}@${proxyHost}`;
const targetUrl = "https://jsonplaceholder.typicode.com/posts";
// 프록시 에이전트 생성
const agent = new HttpsProxyAgent(proxyUrl);
fetch(targetUrl, { agent })
.then((response) => {
if (!response.ok) {
throw new Error(`데이터 가져오기 오류. 상태: ${response.status}`);
}
return response.json();
})
.then((data) => {
console.log("프록시를 통해 가져온 데이터:", data);
})
.catch((error) => {
console.error("프록시 가져오기 오류:", error);
});
이 코드는 HttpsProxyAgent를 사용하여 fetch를 통해 특정 프록시를 경유해 요청을 보냅니다. 이후 프록시 세부 정보를 정의하고 프록시 에이전트를 생성합니다. fetch는 또한 프록시를 통해 대상 URL에서 데이터를 가져옵니다.
프록시를 구성하려면
node-fetch의Fetch API를사용해야 합니다. 자세한 내용은 node-fetch 문서를 참조하세요. 선택한 프록시에 따라 이 코드는 다를 수 있습니다. 최신 정보는 Bright Data 공식 문서를 참조하십시오.
Fetch API 모범 사례
Fetch API 요청 시 효율성과 성능 향상을 위해 다음 모범 사례를 따르십시오:
응답 캐싱
서버 부하를 줄이고 전반적인 사용자 경험을 향상시키기 위해 자주 요청되는 데이터를 저장하는 캐싱 메커니즘을 사용할 수 있습니다. 이렇게 하면 중복된 서버 호출을 피할 수 있습니다. 다음은 네트워크 요청을 수행하기 전에 데이터가 이미 캐시되어 있는지 확인하는 예시입니다:
const cache = new Map();
async function fetchWithCache(url, cacheDuration = 5 * 60 * 1000) { // 기본값: 5분
const cachedData = cache.get(url);
// 캐시된 데이터가 존재하고 유효한지 확인
if (cachedData && (Date.now() - cachedData.timestamp < cacheDuration)) {
console.log("캐시에서 가져옴:", url);
return cachedData.data;
}
try {
console.log("API에서 가져옴:", url);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
const data = await response.json();
// 타임스탬프와 함께 데이터를 캐시에 저장
cache.set(url, { data, timestamp: Date.now() });
console.log("Fetched and cached:", url);
return data;
} catch (error) {
console.error("Fetch error:", error.message);
// API 실패 시, 사용 가능한 경우 오래된 캐시 데이터 반환
if (cachedData) {
console.warn("Returning stale cache data due to error.");
return cachedData.data;
}
throw error; // 캐시 데이터 없음, 오류 재전달
}
}
// 첫 번째 요청 (API에서 가져옴)
fetchWithCache("https://jsonplaceholder.typicode.com/posts")
.then((data) => console.log("첫 번째 가져오기:", data))
.catch((error) => console.error("오류:", error));
// 두 번째 요청 (2초 후 캐시에서 가져옴)
setTimeout(() => {
fetchWithCache("https://jsonplaceholder.typicode.com/posts")
.then((data) => console.log("두 번째 가져오기 (캐시됨):", data))
.catch((error) => console.error("오류:", error));
}, 2000);
// 세 번째 요청 (캐시 만료 후, API에서 다시 가져옴)
setTimeout(() => {
fetchWithCache("https://jsonplaceholder.typicode.com/posts")
.then((data) => console.log("세 번째 요청 (캐시 만료 후):", data))
.catch((error) => console.error("오류:", error));
}, 6 * 60 * 1000); // 6분 후 (캐시 만료)
이미 캐시된 데이터에 대한 불필요한 요청을 방지하면 성능을 개선하고 로드 시간을 단축할 수 있습니다.
타임아웃 처리
일부 타임아웃을 설정하면 Fetch 요청이 무한정 대기하는 것을 방지할 수 있습니다. AbortController를 사용하여 지정된 시간을 초과한 요청을 취소할 수 있습니다. 다음 예시에서는 타임아웃을 3초로 설정했으며, 기본 타임아웃 값은 5초입니다:
async function fetchWithTimeout(url, timeout = 5000, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
console.warn(`시도 ${attempt}: Fetch 요청 시간 초과:`, url);
controller.abort();
}, timeout);
try {
console.log(`시도 ${attempt}: ${url} 가져오기 중`);
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === "AbortError") {
console.error(`시도 ${attempt}: 타임아웃으로 인해 Fetch 요청이 중단되었습니다.`);
} else {
console.error(`시도 ${attempt}: 네트워크 또는 Fetch 오류:`, error.message);
}
if (attempt === retries) {
throw error; // 최대 재시도 횟수 초과 시 실패
}
console.log(`재시도 중... (${attempt}/${retries})`);
}
}
}
// 재시도 기능 테스트
fetchWithTimeout("https://jsonplaceholder.typicode.com/posts", 3000, 3)
.then((data) => console.log("데이터 가져옴:", data))
.catch((error) => console.error("최종 오류:", error));
이렇게 하면 지정된 타임아웃을 초과하는 요청은 중단되고 다른 오류는 적절히 처리됩니다.
요청 스로틀링
API가 요청으로 과부하되지 않도록 요청 빈도를 제어하는 스로틀링을 구현해야 합니다. 따라서 특정 시간 내에 수행할 수 있는 요청 수를 제한해야 합니다. 다음 예제는 함수가 지정된 간격(limit)마다 최대 한 번만 실행되도록 보장하는 스로틀 함수를 생성합니다:
function throttle(func, limit) {
let lastFunc;
let lastRan;
return function (...args) {
const context = this;
if (!lastRan) {
func.apply(context, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(function () {
if (Date.now() - lastRan >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
};
}
const throttledFetch = throttle(async (url) => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log("스로틀링된 데이터:", data);
} catch (error) {
console.error("스로틀링된 요청 오류:", error);
}
}, 2000);
throttledFetch("https://jsonplaceholder.typicode.com/posts");
console.log("2초 후에 다시 가져옵니다...");
throttledFetch("https://jsonplaceholder.typicode.com/posts");
throttledFetch 함수는 throttle 유틸리티를 사용하여 API 요청을 제어합니다. URL에서 데이터를 가져오기 위한 반복 호출 간격을 최소 2초로 유지합니다. 이를 통해 중복되거나 과도한 API 호출을 방지하고, 오류를 처리하며, 가져온 데이터를 기록합니다.
결론
Fetch API는 현대 웹 애플리케이션에서 비동기 작업과 데이터 처리를 단순화합니다. 그러나 대규모 또는 지역 타겟팅 요청을 처리할 때 IP 차단, 속도 제한, CAPTCHA와 같은 문제가 발생할 수 있습니다.
Bright Data의 Scraper API와 Scraping Browser는 이러한 문제에 대한 강력한 해결책을 제공합니다. Scraper API는 안티 스크래핑 방어책을 우회하여 원활한 데이터 추출을 가능하게 하며, Scraping Browser는 자바스크립트 중심의 동적 콘텐츠를 효율적으로 처리합니다. 이 도구들은 가장 복잡한 웹사이트에서도 안전하고 확장 가능하며 신뢰할 수 있는 데이터 수집을 보장합니다.