- Fetch API 요청과 응답
-
는 HTTP 파이프라인을 구성하는 네트워크 요청과 응답 등의 요소를 자바스크립트에서 접근하고 조작할
수 있도록
Headers(요청/응답 헤더),Request(리소스 요청),Response(요청에 대한 응답) 등의 인터페이스를 제공한다.fetch();를 사용하려면; 먼저, API 끝점(엔드포인트)가 필요한데,fetch(URL);메서드로 리소스 요청을 생성하여 비동기적으로 네트워크 리소스를 취득할 수 있다 -
1.
Fetch API는 3단계로 동작한다:
먼저, 컨텐츠를 가져올 URL을 전달하면서
fetch();를 호출한다. 다음, HTTP 응답이 도착하기 시작하면; 1단계에서 비동기적으로 반환한 응답객체를 가져오고, 이 응답객체의 메서드를 호출해 응답바디를 가져온다. 마지막으로, 2단계에서 비동기적으로 반환한 바디객체를 사용해 필요한 일을 수행한다 -
2-1.
가장 단순한 형태의
fetch(URL);는 가져오고자 하는 리소스의 URL 을 나타내는 하나의 인수만 받아서 프라미스로 반환하는데(여기에 응답 body까지 모두 포함되어 있지는 않다!), 반환된 Response 객체에서 JSON 본문 콘텐츠를 추출하기 위해서는; 다시json();메서드를 호출해야 하며,json();은 응답 body를 JSON으로 파싱한 결과로 이행하는 또 다른 프로미스를 반환하게 된다 -
2-2.
fetch(URL);는 네트워크에서 리소스를 취득하기 위한 요청을 시작하고, 응답이 사용 가능해지면; Response 객체로 '이행'하는 프로미스를 반환한다 - 곧,fetch(URL);은 가져오려는 리소스 URL 을 매개변수로 받아 해당 요청에 대한 응답으로 이행하는 프라미스를 반환하는데, 서버로부터 헤더를 포함한 응답을 받는 순간 즉시 '이행'한다(이는 서버가 HTTP 오류 코드로 응답해도 '이행'한다는 의미이다!)
const f= fetch('https://jsonplaceholder.typicode.com/posts/1')
console.log(f) // Promise { <pending> } ← 프라미스가 '대기'(pending) 중임..
☞ 프라미스가 '대기'(= pending) 중이니 콘솔을 열어보십시오..
Headers 객체(= 응답 객체의 headers 프로퍼티)는
has(); 메서드로 존재 여부를 확인하거나
get(); 메서드를 써서 헤더의 값을 읽어올 수 있다.
Headers 객체는 이터러블이므로 다음과 같이 헤더를 읽을 수도 있다:
fetch(url).then(response => {
for (let [name, value] of response.headers) {
console.log(`${name}: ${value}`)
}
});
fetch("./api/users/current") // HTTP GET 요청
.then(response => response.json()) // 응답 바디를 JSON 객체로 파싱한다
.then(User => { // 파싱된 객체를 사용한다
displayUserInfo(User) // 내용 출력
});
async function isServiceReady() {
let response= await fetch("./api/service/status")
let body= await response.text() // 텍스트 데이터 가져오기
return body === "ready";
}
async function logJSONData() {
const response= await fetch("https://jsonplaceholder.typicode.com/todos/1");
const jsonData= await response.json();
console.log(jsonData)
}
logJSONData() // {completed: false, id: 1, title: 'delectus aut autem', userId: 1}
fetch('https://jsonplaceholder.typicode.com/todos/1') // fetch()로 서버에 GET 요청을 하고..
.then(response => { // 서버측 응답이 오면(곧, 네트워크 접속 오류는 아니다!); 우선,
if (! response.ok) { // 예상할 수 있는 에러(우선, HTTP 에러)를 처리한다
throw new Error(`HTTP 에러! ${response.status}`);
} // IF 조건에서 데이터 타입이 맞는지 등도 추가적으로 체크해줄 수 있다!
return response.json(); // 성공 시: 바디를 파싱하여 다음 단계로 '이행'할 프라미스를 반환한다
}).then(todo => { // 프라미스가 '해석'되면; 원하는 작업을 수행하도록 한다
console.log(todo.title) // delectus aut autem
}).catch(e => { // 예기치 못한 에러를 처리한다
console.log(e)
});
☞
웹서버가 fetch(); 요청에 응답한다면(오직 네트워크 접속불가 등의 심각한 오류가 있을 때만 '거부'되며, 404 등의 HTTP 오류 시는 '거부'하지 않는다!);
프라미스는 즉시 '이행'되는데, 이에 fetch();는 HTTP 상태와 응답헤더를 받는 즉시
(응답바디는 아직 도착하지 않았지만!)프라미스를 '해석'한다
←
그러므로, .then(); 처리기는 반드시
Response.ok(= 서버의 응답을 받음)
및 Response.status 속성을 확인해야 한다!
* cf)
아직 완료되지 않은 fetch(); 작업을 취소하려면 new AbortController();
및 AbortSignal 인터페이스를 사용할 수 있다:
const controller= new AbortController();
const signal= controller.signal
const url= "video.mp4"
const downloadBtn= document.querySelector("#download")
const abortBtn= document.querySelector("#abort")
downloadBtn.addEventListener("click", async () => {
try {
const response= await fetch(url, { signal });
console.log("다운로드 완료", response)
} catch(error) {
console.error(`다운로드 오류: ${error.message}`)
}
});
abortBtn.addEventListener("click", () => {
controller.abort()
console.log("다운로드 중단됨")
});