fetch 실행 시 프로미스의 응답 헤더에 관하여

타래·2023년 11월 18일
0

노션 클로닝 과제를 진행하며 있었던 일이다.

const request = async (url) => {
  try {
    const res = await fetch(`${API_END_POINT}${url}`);

    if (!res.ok) {
		// 에러처리 1
    }
    return await res.json();
  } catch (e) {
	// 에러처리 2
  }
};

fetch()로 url에 있는 api 데이터를 가져오려는 코드이다.
에러 체크 후, res.ok 일때만 데이터를 리턴하는 코드이다.
처음에는 HTTP 에러 (400, 500번대)만 제하면 되겠지하고 안일하게 생각했다.

이후 멘토님의 코드리뷰 덕분에 한 번 더 생각하게 되었고, 관련된 자료를 찾아보게 되었다.
위 코드의 흐름에 맞춰 자료를 조금 더 찾아보았다.


fetch 실행 순서

fetch()를 호출했을 때 부터 순서대로 나열해보자.

  • fetch()를 호출하면 브라우저는 네트워크 요청을 보내고 프라미스가 반환된다.
    (위 코드에는 res에다가 반환.)

  • 서버에서 응답 헤더를 받자마자, fetch 호출 시 반환받은 promise가 내장 클래스 Response의 인스턴스와 함께 이행 상태가 된다.

    • 이행 상태는 CORS 에러나 네트워크 요청 자체의 실패가 아닌 이상, status에 관계없이 이행된다.

    • 이때 내장 클래스 Response의 인스턴스는

      {
      // 프로퍼티
      	'status' // HTTP 응답 상태 코드 (예: 200, 404, 500).
      	'ok' // 상태 코드가 200-299 범위에 있는지 여부를 나타내는 부울 값.
      	'statusText' // HTTP 상태 메시지 (예: "OK", "Not Found").
      	'headers' // 응답 헤더를 나타내는 Headers 객체.
      	'url' // 응답이 온 URL.
      
      // 메서드
      	text() // 응답 본문을 텍스트로 반환하는 메서드.
      	json() // JSON으로 파싱된 응답 본문을 반환하는 메서드.
      	blob() // 응답 본문을 Blob 객체로 반환하는 메서드.
      	formData() // 응답 본문을 FormData 객체로 반환하는 메서드.
      	arrayBuffer() // 응답 본문을 ArrayBuffer로 반환하는 메서드.
      }

      등이 있다.

      이 단계는 아직 본문(body)이 도착하기 전이지만, status를 통해 요청이 성공적으로 처리되었는지 아닌지를 확인할 수 있다.

  • 이후 res에 Response 객체 ( 위 코드에서는 res.json() ) 등을 통해 응답을 반환한다.


res.ok가 200~299 범위의 여부를 확인한 후 boolean 값을 리턴하는 프로퍼티라는 것을 알게되었
다.


에러처리

이제 fetch 실행 순서에 대하여 조금 더 잘? 알게된 것 같다.
이제 남은 것은 각 상황에 맞는 에러처리를 잘 해주는 것.

각각의 에러 상황에 대하여 찾아보았다.

  • 에러처리 1 : status가 400번 or 500번대의 비성공 상태에 대한 에러처리
  • 에러처리 2 : 아까 이행 상태에 대하여 얘기하던 부분, CORS 에러나 서버에 요청이 완전히 서버에 도달하지 못하는 경우에 대한 에러처리

에러처리 1

아까, 200~299번 사이의 범위일 때 ok가 true를 리턴한다고 했다.
번호별로 각각의 성공 사례? 가 모두 다르더라.
현재와 같은 일반적인 상황 외에 번호별의 특수한 경우에는 status에 따라 다른 문구 혹은 동작을 수행하게끔 하면 좋겠다고 생각했다.

문제는 비성공 상태에 대한 처리.
400번대 갯수만 해도 29개이고 500번대도 11개이다.
(더럽게 많다. 200번대는 10개가 채 안되는데..)
그렇다면 나는 총 40여개의 status별 에러처리를 해야하는 것인가?

...일단은 에러코드들이 어떤 내용들일지 한번 읽어보았다.

400번: 클라이언트의 요청이 유효하지 않아 발생하는 상태라고 한다.

  • 401: 인증과 관련된 문제, 비인증.
  • 402: 비표준, 결제와 관련된 문제
  • 403: 클라이언트가 권한이 없을때.
    (비회원일때, 회원 전용 페이지에 접근한다거나 관리자 페이지에 접근한다거나)
  • 404: 서버가 요청받은 리소스를 찾을 수 없는 상황.
  • 418: 이상한 농담..?
  • ... 기타 등등

공식문서를 찾아보며 위 상태들에 대하여 공통점이 있을 경우, 그 상태들을 묶어서 에러에 대처하면 어떨까 하고 생각해서 찾아봤는데..
상태들마다 각각의 에러가 발생할 수 있는 상황에 대처하기 위해 존재하는 것 같아, 공통점을 찾기가 쉽지 않았다.

가장 좋은 에러처리는 현재 fetch()를 사용하는 코드가 인증과 관련된 코드인지, 결제에 관련한 코드인지 등을 파악한 후 거기에 맞는 status를 찾아서 끼워넣는게 좋아보인다.

내 노션 클론의 경우

url이 abc/cde 처럼 존재하지 않을 경우 (존재하지 않는 경로), 
/documents/:${id} 에서 id값이 존재하지 않을 경우 (존재하지 않는 자원)
: 404 에러처리

로그인 기능을 구현 했을 경우
비회원이 회원의 글을 읽으려하면 : 401 에러처리.
다른 사람이 쓴 글을 수정하려하면 : 403 예러처리.

등의 에러처리를 할 수 있을 것 같다.

이 외에도 자체 에러코드를 만들거나 하는 경우도 있다고 한다.
그리고 404등 500 오류등 모든오류는 그냥 바로 오류메시지 보여주지말고 오류메시지는 절때 친절하면안된다고 한다. 해킹에 요인이 된다고.

에러처리 2

보안, url 문제, CORS, 네트워크 연결 문제 등과 관련된 에러다보니, e.message로 처리하는 것이 좋아보인다.

결론

HTTP status에 대한 에러처리에 대하여 살짝 알아보았다.
예전에 마광휘 개발자님께서 추천해주신 책 중에 'HTTP 완벽 가이드'가 있었다.
프론트도 서버에 관하여 알아야 한다고... 그 말씀이 조금 이해가 되는 것 같았다.

0개의 댓글