HTTP 응답 상태 코드
아래 코드에서 response.status 는 'HTTP 응답 상태 코드'로서 응답 상태 코드는 웹 서버가 요청을 받은 후 처리한 결과를 클라이언트에게 알려주는 '세 자리 숫자'를 뜻한다.
대표적인 예시로 에러가 생겼을 때 나오는 404가 있다.
아래 코드에 나오는 200은 "OK"를 의미한다. 이는 서버가 클라이언트의 요청을 성공적으로 처리하고 요청된 정보를 정상적으로 반환했다는 뜻이다.
따라서 response.status == 200은 서버가 요청을 성공적으로 처리했을 때 true 가 된다.
class HttpError extends Error {
constructor(response) {
super(`${response.status} for ${response.url}`);
this.name = 'HttpError';
this.response = response;
}
}
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
})
}
function narutoIsNotOtaku() {
let title = prompt("애니메이션 제목을 입력하세요.", "naruto");
return loadJson(`https://animechan.xyz/api/random/anime?title=${title}`)
.then(res => {
alert(`${res.character}: ${res.quote}.`);
return res;
})
.catch(err => {
if (err instanceof HttpError && err.response.status == 404) {
alert("일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!");
return narutoIsNotOtaku();
} else {
throw err;
}
});
}
narutoIsNotOtaku();
이 코드를 async/await 로 리팩토링 하려고 하는데,
먼저, loadJson 함수 부분을 아래와 같이 수정했다. 그런데 역시 이해도가 부족한 탓인가 오류는 없었지만 정상적으로 작동하지 않았다.
문제점은 무엇일까?
async function loadJson(url) {
let response = fetch(url);
await ((response) => {
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
});
}
await 문법 오류:
await 키워드는 await 뒤에 오는 함수가 반환하는 Promise가 완료될 때까지 기다린다. 때문에 await가 fetch 아랫 부분이 아니라, fetch 앞에 왔어야 한다.
내가 수정한 코드에서는 await가 제대로 동작하지도 않을 뿐더러
fetch가 반환하는 Promise를 처리하기 전에 바로 다음 코드로 넘어가기 때문에 Promise를 처리하는 부분이 누락되어 있다. 그러므로 Promise를 처리하기 전에 await를 사용하여 fetch의 결과를 해결(resolve)해야 한다
따라서 아래와 같이 수정해야 한다.
async function loadJson(url) {
let response = await fetch(url); // fetch의 결과를 기다림
if (response.status == 200) {
return response.json(); // 응답이 200 ("OK")인 경우 JSON 데이터 반환
} else {
throw new HttpError(response); // 응답이 200 OK가 아닌 경우 HttpError 발생
}
}
그리고 이 코드에 뒤이어서
narutoIsNotOtaku() 함수 부분도 수정을 했는데
async function narutoIsNotOtaku() {
let title = prompt("애니메이션 제목을 입력하세요.", "naruto");
res = await loadJson(`https://animechan.xyz/api/random/anime?title=${title}`);
res.catch((err) => {
if (err instanceof HttpError && err.response.status == 404) {
alert(
"일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!"
);
return narutoIsNotOtaku();
} else {
throw err;
}
});
alert(`${res.character}: ${res.quote}.`);
return res;
}
이것 역시도 문제가 많다.
'catch' method 사용 오류:
loadJson가 비동기 함수(async function)이기 때문에 반환된 결과는 Promise 객체이다. 이 경우 'try' ... 'catch' 문을 사용하여 오류를 처리해야 한다.
try {
} catch {
}
async function 호출 오류:
narutoIsNotOtaku 함수 내에서 loadJson 함수를 호출한 후에 바로 catch 메서드를 호출하고 있다. 이는 비동기적인 작업의 결과를 기다리지 않고 바로 다음 코드를 실행하는 문제를 발생시킨다.
try 안에 await 부분을 넣어야 한다.
응답 처리 오류:
loadJson 함수가 반환한 Promise를 처리하는 부분이 필요하다. 응답이 성공하면 캐릭터와 명대사를 알림창으로 보여주는 코드가 await가 있는 함수 바로 다음 줄에 나와야 한다.
제대로 수정을 하면,
async function narutoIsNotOtaku() {
// 애니메이션 제목을 입력하는 프롬프트 창을 띄운다.
let title = prompt("애니메이션 제목을 입력하세요.", "naruto");
try {
// loadJson의 결과를 기다림 -> 비동기 함수이기 때문에 Promise 객체 반환
let res = await loadJson(
`https://animechan.xyz/api/random/anime?title=${title}`
);
// loadJson 함수의 response가 성공적으로 반환되면, 캐릭터와 명대사를 알림창으로 보여준다.
alert(`${res.character}: ${res.quote}.`);
return res;
} catch (err) {
// 비동기 함수의 Promise 객체는 try...catch 문을 사용하여 오류를 처리해야 한다.
if (err instanceof HttpError && err.response.status == 404) {
alert(
"일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!"
);
// narutoIsNotOtaku 함수를 재실행 하여 프롬프트 창을 다시 띄운다.
return narutoIsNotOtaku();
} else {
throw err;
}
}
}
정리를 하자면,
- async 함수는 항상 Promise 를 반환한다.
- await 뒤에 있는 건 항상 Promise 다.
- await Promise 는 Promise Result를 반환하며 약속이행이 될 때 까지 기다린다.