HTTP 프로토콜과 fetch API

나혜수·2023년 2월 14일
0

자바스크립트 실전

목록 보기
11/19

✅HTTP 프로토콜

HTTP 요청과 응답


RFC 2616으로 발표된 HTTP 1.1 버전은 클라이언트의 요청 Request과 서버의 응답 Response에 의해 동작하는 아주 간단한 프로토콜이다. 클라이언트는 요청을 보내는 쪽으로 브라우저를 의미한다. 서버는 요청을 받는 쪽으로 데이터를 보내주는 원격지의 컴퓨터를 의미한다. 동작 원리는 다음과 같다.

  • HTTP 클라이언트가 서버에 요청을 전송한다. 요청 내용에는 프로토콜 명령에 해당하는 요청 메소드, URL, HTTP 버전이 포함되며 기타 클라이언트 요청과 부가 정보도 포함된다.

  • HTTP 서버는 요청의 처리 결과를 의미하는 응답 코드가 포함된 상태 정보를 회신한다. 클라이언트가 요청한 결과물, 기타 정보도 함께 회신한다.


MIME 유사 메세지

HTTP의 Request, Response 메세지는 MIME 유사 구조를 사용해 데이터를 전송한다.

MIME (Multipurpose Internet Mail Extensions)
이미지, 동영상 파일등은 바이너리 데이터 (0 & 1)에 속한다. 초기 이메일 시스템에서는 아스키 코드로만 주고받을 수 있었기 때문에, 본문의 텍스트 뿐만 아니라 첨부 파일도 전송하기 위해서 바이너리 데이터인 첨부파일을 아스키코드로 인코딩하는 방법을 찾아야 했다.
Multipurpose Internet Mail Extension 을 직역하면 다목적 인터넷 메일 확장이다. 즉, 바이너리 데이터인 첨부파일들을 아스키코드로 인코딩하여 본문에 덧붙이겠다는 뜻이다. (Extension) 전송 시 인코딩된 바이너리 데이터가 어떤 타입인지 명시해주어야 수신 측에서 그 타입대로 해석한다. 현재는 이메일 뿐만 아니라 웹을 통해 HTTP 통신에서 전달되는 다양한 형태의 데이터를 표현하기 위해 사용되고 있다.

인코딩 Encoding : 바이너리 파일에서 텍스트파일로 변환
디코딩 Decoding : 텍스트파일을 바이너리 파일로 변환

MIME로 인코딩한 파일은 Content-type 정보를 파일 앞부분에 담는다. Content-type은 MIME로 인코딩하고 있는 데이터의 종류를 설명하며 여러가지 타입이 있다.



요청 메세지

클라이언트가 보내는 요청 메세지는 ①요청문, ②헤더 (부가 정보), ③바디 (실제 데이터) 로 구성된다.

요청문에의 내용은 요청 메소드, URL, HTTP 버전으로 구성된다.

헤더는 클라이언트와 서버 사이의 부가 정보를 전달하는 목적으로 사용되며, 형식은 <헤더 이름> : <헤더값> 이다. 요청과 응답에 공통으로 사용되는 General, Response Headers, Request Headers 로 구분된다.

HTTP 요청 메서드

URL을 이용하면 서버에 특정 데이터를 요청할 수 있다. 요청하는 데이터에 특정 동작을 수행하고 싶으면 HTTP Request Methods를 이용한다. 주요 메소드는 다음과 같으며 데이터에 대한 조회, 생성, 변경, 삭제 동작을 HTTP 요청 메서드로 정의할 수 있다.

GET : 존재하는 자원에 대한 요청
POST : 클라이언트가 서버에 정보를 전송할 수 있게 한다.
PUT : 존재하는 자원에 대한 변경
DELETE : 존재하는 자원에 대한 삭제



URL (Uniform Resource Locators)

방대한 컴퓨터 네트워크에서 원하는 정보 자원을 찾기 위해서는 해당 정보 자원의 위치와 종류를 정확히 파악할 필요가 있는데, 이를 나타내는 일련의 규칙을 URL이라고 한다.
즉, 서버에 자원을 요청하기 위해 입력하는 영문 주소로 숫자로 되어 있는 IP 주소보다는 훨씬 기억하기 쉽다.

응답 메세지

클라이언트로부터 요청 메세지를 수신한 서버는 해당 요구를 처리한 후 그 결과를 응답 메세지 형식으로 회신한다. 응답 메세지의 구조는 요청 메세지와 거의 동일한데, 요청문 대신 처리 결과를 의미하는 상태문을 사용한다. 상태문은 HTTP 버전, 상태 코드, 상태 이름으로 구성된다.

HTTP 상태 코드

URL과 요청 메소드가 클라이언트에서 설정해야 할 정보라면 HTTP 상태 코드는 서버에서 설정해주는 응답 정보이다. 예를 들어 http://domain.com/users 사용자 목록을 받아오는 GET 요청을 보내면, 서버에서 응답으로 오는 상태 코드는 크게 2개로 나뉜다. → 200 or 404
상태 코드는 200번대부터 500번대까지 다양하게 있지만 주요한 상태 코드만 몇 개 살펴보자.

  • 2xx - 성공
    200번대의 상태 코드는 대부분 성공을 의미한다.

    200 : GET 요청에 대한 성공
    204 : No Content. 성공했으나 응답 본문에 데이터가 없음
    205 : Reset Content. 성공했으나 클라이언트의 화면을 새로 고침하도록 권고
    206 : Partial Conent. 성공했으나 일부 범위의 데이터만 반환

  • 3xx - 리다이렉션
    300번대의 상태 코드는 대부분 클라이언트가 이전 주소로 데이터를 요청하여 서버에서 새 URL로 리다이렉트를 유도하는 경우이다.

    301 : Moved Permanently, 요청한 자원이 새 URL에 존재
    303 : See Other, 요청한 자원이 임시 주소에 존재
    304 : Not Modified, 요청한 자원이 변경되지 않았으므로 클라이언트에서 캐싱된 자원을 사용하도록 권고. ETag와 같은 정보를 활용하여 변경 여부를 확인

  • 4xx - 클라이언트 에러
    400번대 상태 코드는 대부분 클라이언트의 코드가 잘못된 경우이다. 유효하지 않은 자원을 요청했거나 요청이나 권한이 잘못된 경우 발생한다. 가장 익숙한 상태 코드는 404 코드로 요청한 자원이 서버에 없다는 의미이다.

    400 : Bad Request, 잘못된 요청
    401 : Unauthorized, 권한 없이 요청. Authorization 헤더가 잘못된 경우
    403 : Forbidden, 서버에서 해당 자원에 대해 접근 금지
    405 : Method Not Allowed, 허용되지 않은 요청 메서드
    409 : Conflict, 최신 자원이 아닌데 업데이트하는 경우. ex) 파일 업로드 시 버전 충돌

  • 5xx - 서버 에러

    501 : Not Implemented, 요청한 동작에 대해 서버가 수행할 수 없는 경우
    503 : Service Unavailable, 서버가 과부하 또는 유지 보수로 내려간 경우


HTTP 동작 과정




✅Fetch API

Fetch API는 HTTP 파이프라인을 구성하는 request, response 등의 요소를 JavaScript에서 접근하고 조작할 수 있는 인터페이스를 제공한다. Fetch API가 제공하는 fetch( ) global 메소드로 네트워크의 리소스를 쉽게 비동기적으로 가져올 수도 있다.

+ 이전에는 이런 기능을 XMLHttpRequest 를 사용해 할 수 있었다.
+ fetch( ) 함수는 엄밀히 말해, 브라우저의 window 객체에 소속되어 있기 때문에 window.fetch( )로 사용되기도 한다.

fetch 사용법

fetch( ) 함수는 첫번째 인자로 URL (API 요청을 받는 백엔드 주소), 두번째 인자로 옵션 객체를 받고, Promise 타입의 객체를 반환한다. API 호출이 성공했을 경우에는 response 객체를, 실패했을 경우에는 예외 (error) 객체를 반환한다.

fetch(url, {options})
  • request 객체는 클라이언트를 통해 서버에 요청하는 정보를 담고있는 객체이다.
  • response 객체는 서버가 클라이언트의 요청에 응답하는 정보를 담고 있는 객체이다.

옵션 객체에는 HTTP Request Method, HTTP Request Headers, HTTP Request body 등을 설정하여, response 객체로부터 HTTP 응답 상태, HTTP Response Headers, HTTP Response body 등을 읽어올 수 있다.

🐣 예시

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(json => console.log(json))
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

위 코드는 네트워크에서 JSON 파일을 가져와 콘솔에 출력한다. Response는 HTTP 응답 전체를 나타내는 객체로, JSON 본문 콘텐츠를 추출하기 위해서는 json( ) 메소드를 호출해야 한다. json( )은 Response body 텍스트를 JSON으로 파싱한 또 다른 프로미스를 반환한다.


response 객체에는 json( ) 메소드 외에도 여러 가지 메소드가 있다.
blob( )은 이미지를 처리하는데 쓸 수 있다.

fetch(imageUrl)
    .then(res => {
        return res.blob()
    })
    .then(blob => {
        console.log(blob)
        const objectURL = URL.createObjectURL(blob)
        console.log(objectURL)
        $image.src = objectURL

        document.querySelector('body').appendChild($image)
    })


⭐ fetch api는 HTTP error가 발생하더라도 reject 되지 않는다. 네트워크 에러나 요청이 완료되지 못한 경우에만 reject 되기 때문에 response의 status code or ok를 체크해주는 것이 좋다.


ex) 존재하지 않는 api 호출해보기

// res.ok는 status가 200~299 사이인 경우 true
    fetch('http://undefined.no.no/no-api')
    .then(res => {
        if(res.ok) {
            return res.json()
        }
        throw new Error('요청을 처리하지 못했어요.') // else 생략 
    })
    .then(result => {
        console.log(result)
    })
    .catch(e => alert(e.message))

GET 호출

먼저 단순히 원격 API에 있는 데이터를 가져올 때 쓰이는 GET 방식의 HTTP 통신을 살펴보자.
fetch( ) 함수의 default method는 GET이며, GET 방식은 요청 전문을 받지 않기 때문에 옵션 인자가 필요없다.


JSON Placeholder 라는 인터넷에 공개된 API를 사용해서 예제 코드를 작성해보자.

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => console.log(response)
);

Response 객체를 통해 응답 상태가 '200 OK' 인 것을 알 수 있다.
대부분의 REST API들은 JSON 형태의 데이터를 응답하기 때문에 Response 객체는 json( ) 메소드를 제공한다.

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json())
  .then((data) => console.log(data));

json( ) 메소드를 호출하면, Response 객체로부터 JSON 형태의 응답 전문을 자바스크립트 객체로 변환하여 얻을 수 있다.

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio",
  "body": "quia et suscipit↵suscipit eveniet architecto"
}


POST 호출

원격 API에서 관리하고 있는 데이터를 생성해야 한다면 요청 전문을 포함할 수 있는 POST 방식의 HTTP 통신이 필요하다.

이번에는 새로운 포스팅를 생성하기 위해서 fetch() 함수를 사용해보자. method 옵션을 POST로 지정해주고, headers 옵션을 통해 JSON 포멧을 사용한다고 알려줘야 하며, 요청 전문을 JSON 형식으로 직렬화화여 가장 중요한 body 옵션에 설정해준다.

fetch("https://jsonplaceholder.typicode.com/posts", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    title: "Test",
    body: "I am testing!",
    userId: 1,
  }),
}).then((response) => console.log(response));

마찬가지 방법으로 json( ) 메소드를 호출하면 응답 전문을 객체 형태로 얻을 수 있다.

PUT, DELETE 호출

원격 API에서 관리하는 데이터의 수정과 삭제를 위해서 PUT과 DELETE 방식의 HTTP 호출을 해야할 때가 있다.

PUT 방식은 method 옵션만 PUT으로 설정한다는 점 빼놓고는 POST 방식과 매우 흡사하다.

fetch("https://jsonplaceholder.typicode.com/posts/1", {
  method: "PUT",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    title: "Test",
    body: "I am testing!",
    userId: 1,
  }),
})
  .then((response) => response.json())
  .then((data) => console.log(data));

DELETE 방식에서는 보낼 데이터가 없기 때문에 headers와 body 옵션이 필요없다.

fetch("https://jsonplaceholder.typicode.com/posts/1", {
  method: "DELETE",
})
  .then((response) => response.json())
  .then((data) => console.log(data));
profile
오늘도 신나개 🐶

0개의 댓글