HTTP 조금만 더 알아보자.

Junbro·2022년 6월 28일
0

네트워크

목록 보기
1/4
post-thumbnail

1. HTTP란?

  • HTTP는 하이퍼텍스트 전송 프로토콜(HyperText Transfer Protocol)이다.
  • 클라이언트가 하나의 요청을 보낸후 서버로 부터 응답을 받는 모델이다.
    • 이것이 중요한 포인트이다. 만약 여러 요청을 보낸후 처리가 빠른 순서대로 응답을 받는다면 요청과 그에 해당하는 응답을 구분하기 위한 상태,플래그가 존재해야 할 것이다.
    • http가 다른 응용 프로토콜을 제치고, 웹에서 널리 사용되는 이유중의 하나이다.
  • Stateless 프로토콜이다.
    • 이 특징은 서버가 상태 정보를 저장하거나, 추적할 필요가 없다는 것이다.

    • 이러한 특징으로 서버를 100개 넘게 확장하여도 상태 관리를 해줄 필요가 없기때문에 확장시 부담이 줄게된다.

    • 왜냐하면 클라이언트는 서버에 요청을 보낼 때 매번 지금 요청이 처음인것처럼 상태 정보를 담아서 보내주기 때문이다.

    • HTTP 와는 다르게 연결상태를 유지하는 FTP(파일 전송 프로토콜) 응용 계층 프로토콜이 존재한다.

      StatefFul
      손님: 아이스 아메리카노 얼마인가요?
      스벅 직원: 5000원 입니다.
      손님: 2개 주세요.
      스벅 직원: 10000원 입니다. 결제는 무엇으로 하시겠습니까?
      손님: 기프티콘이요.
      스벅 지원: 결제 완료 되었습니다.

      Stateless
      손님: 아이스 아메리카노 얼마인가요?
      스벅 직원: 5000원 입니다.
      손님: 2개 주세요.
      스벅 직원: 무엇을 2개 달라는 거죠?

    • 확장성이 좋다는 장점이 있지만, 모든 요청에 정보를 담아서 보내야 하므로 요청 패킷에 헤더정보가 많아진다는 단점이 존재한다.


  • ‘Protocol’이라고 하여 거창한 것이 아니라, 영향력 있는 단체, 사람들이 앞으로 웹에서 통신할 때 이렇게 주고받자! 라고 정한 ‘약속’에 지나지 않는다.
  • 이러한 통일된 약속이 없고 개별적인 규칙을 만들어서 통신하였다면, 그에 맞춰 클라이언트, 서버 모두 개별 버전을 개발해야 했을 것이다.
  • 그렇다면 지금처럼 웹이 빠르게 발전하지 못했을 거라고 예상한다.

2. 실제 HTTP 패킷은 어떻게 생겼을까?

1. Wireshark를 통한 패킷 분석

  • Wireshark란?
    • Wireshark는 네트워크 패킷 분석 프로그램이다.

    • 네트워크 통신을 캡처하여 모니터링 할 수 있다.

    • 무료이고, GUI도 깔끔하여 초보자도 쉽게 사용할 수 있다.

    • 프로토콜 분석, 개발, 교육에 다양하게 쓰인다.

      Wireshark · Go Deep.

  • 간단하게 클라이언트가 이미지를 요청하는 하나의 요청-응답 과정이다.

  • 단순히 HEX 데이터로 이루어진 것을 볼 수있다.
  • 다른 프로토콜과의 차이점으로는 간단하고, ‘human readable’ 하다는 것이다.
    • 위에서 보는것과 같이 변환된 메시지가 사람이 읽을 수 있는 문자들로 구성되어 있다.
  • 크게 요청 라인(GET ...), 요청 헤더, 바디로 이루어져 있다.

2. 그렇다면 우리는 HTTP 패킷을 어떻게 해석할까?

  • 위에 요청 뒤에 오는 응답 패킷을 보자.

  • ‘CRLF’를 기준으로 각각의 헤더 정보를 구분하고 있는것을 볼 수있다.
  • 그렇다면 헤더와 바디는 어떻게 구분할까?

  • 위에서 보는것과 같이 ‘Accept-Ranges’ 헤더과 끝이나고 CRLF(\r\n)가 오는 것을 볼 수 있다.
  • 그리고 한번 더 CRLF(\r\n)가 오는데 이것은 헤더와 바디를 구분하는 newLine이다.
  • 간단하게 \r\n\r\n 문자로 헤더와 바디를 구분한다고 생각하면 좋을거 같다.
  • 이렇게 어떤 기준으로 구조를 분해하여 원하는 형태로 조립하는 것을 파싱(Parsing)이라고 한다.
  • 자바스크립트 내장 API(Fetch 등)에서 이러한 기준으로 파싱된 결과를 우리에게 JSON 객체로 전달해준다.
const res = await fetch(uri, {
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
  });

const data = await res.json();

3. HTTP 헤더 직접 이용해보자!

HTTP에는 다양한 헤더가 존재한다.

HTTP 헤더 - HTTP | MDN

이 중에서 자주 사용되는 헤더를 직접 응용하는 케이스를 작성해보았다.

1. Authorization

  • 인증 토큰을 서버로 보낼 때 사용하는 헤더이다.

  • 깃허브 API를 사용하는 경우 인증 토큰을 실어 요청을 보내지 않으면 시간당 60회로 요청이 제한된다.

  • 아래와 같이 깃허브 API에 요청을 보낼 때 ‘Authorization’ 헤더에 깃허브에서 생성한 토큰을 넣어주면 개발시 요청회수를 늘려 테스트를 진행할 수 있다.
async function request(uri) {
  const response = await fetch(uri, {
    headers:{
      'Authorization': 'token ' + GITHUB_ACCESS_TOKENS
    }
  });

  return response.json();
}

request(`https://api.github.com/users/${username}${defaultParams}`);

2. If-None-Match

  • 먼저 이 헤더를 이해하기 전에 ‘ETag’를 알아야 한다.
  • Etag는 쉽게 말하면 내가 받은 응답 버전에 대한 식별자이다.
  • API를 통해 받은 응답이 바뀌지 않았다면 서버에서는 동일한 Etag를 줄것이다.
  • ex:) ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4
  • 만약 해당 응답이 어떠한 동작(Update, Delete)으로 인해 바뀌었다면 서버는 새로운 Etag를 생성해서 새로운 응답과 함께 보내줄 것이다.

ETag - HTTP | MDN

  • 이 때 요청 헤더에 ‘If-None-Match’에 특정 Etag값을 담아 보낸다면 서버에 해당 Etag가 없을 때만 200 응답코드와 함께 클라이언트 요청에 대한 응답을 보낼 것이다.
  • 만약 해당 Etag값이 존재한다면 304 응답코드(Not Modified)만 보내고 응답리소스는 보내지 않을 것이다.
  • 쉽게 말해 ‘If-None-Match’ 헤더는 ‘내가 지금 요청한 리소스가 변경되었다면 최신 응답을 보내다오.’ 라는 뜻이다

If-None-Match - HTTP | MDN

  • 클라이언트에서는 이 헤더를 통해 캐시를 이용할 수 있는 명분을 만들 수 있다.

  • 캐시를 이용하여 서버와의 통신을 효율적으로 이용하여 웹 성능을 높일 수 있다.

  • 말이 어려웠다.. 예시를 통해 어떤 느낌인지만 이해해도 나중에 문서를 찾아보고 사용할 때 도움이 될것이라 생각한다.

  • Youtube API를 통한 예시를 살펴보자

시작하기 | YouTube Data API | Google Developers

  • Youtube API를 통해서 특정 비디오에 대한 정보를 받아오고 싶을 때 코드이다.
export const searchVideo = async (id) => {
  const YOUTUBE_URL = `https://www.googleapis.com/youtube/v3/videos?key=${YOUTUBE_API_KEY}&part=snippet&id=${id}`;

  const res = await fetch(YOUTUBE_URL, {});
  const data = await res.json();

  return data;
};

  • 위에서 보는것과 같이 특정 ‘videoId’에 관한 정보를 요청해서 받았을 때 응답에 ‘etag’가 존재하는 것을 알 수있다.

  • 하지만, 이렇게 계속 요청을 보낸다면 해당 비디오의 정보가 바뀌지 않았는데도 불구하고, 사용자가 해당 비디오를 클릭했을 때 서버는 계속 동일한 응답을 줄 것이다.

  • 리소스가 바뀌지 않았는데 동일한 요청-응답을 주고받는 것이 매우 비효율적으로 보인다.

  • 이제 요청을 보낼 때 이전에 응답으로 받은 eTag를 이용하여 ‘If-none-Match'헤더에 값으로 설정해주고, 두번째 요청을 보내보자.

export const searchVideo = async (id, eTag) => {
  const YOUTUBE_URL = `https://www.googleapis.com/youtube/v3/videos?key=${YOUTUBE_API_KEY}&part=snippet&id=${id}`;

  const res = await fetch(YOUTUBE_URL, {
    headers: {
      "If-None-Match": eTag,
    },
  });
  const data = await res.json();

  return data;
};

  • 아직 침착맨이 해당 비디오를 업데이트 하지 않았기 때문에 YouTube API 서버에서는 해당 비디오에 관한 동일한 ‘eTag’를 가지고 있으므로, ‘304 응답코드(Not Modified)’를 보냈다.

  • 그럼 이제 클라이언트 단에서 첫번째 요청에 대한 응답을 캐싱하여 사용자가 다시 동일한 비디오를 클릭했을 때 ‘‘304 응답코드(Not Modified)’을 확인하고, 캐싱된 데이터를 활용하여 사용자에게 보여주면 될 것이다.

  • 실제로 리소스의 캐시를 검증을 위해 17바이트만의 네트워크 송수신을 주고받을 것을 볼 수 있다.

4. 정리

지금까지 HTTP를 평소보다 조금 더 살펴보았다.

HTTP가 무엇이고, 실제 HTTP가 단순히 HEX 데이터로 이루어진 것을 눈으로 확인했다.

또, HTTP 헤더 중 ‘Authorization', ‘If-None-Match'를 어떻게 사용할 수 있는지 직접 테스트 해보았다.

HTTP에 기본적인 내용들은 MDN, 개인 블로그에 자세하게 설명되어 있으므로 찾아보면 방대하게 나올 것이다.

우리가 자바스크립트를 통해 보내는 HTTP 요청과 응답의 내면이 어떤식으로 이루어졌는지 알면 나의 코드를 더 넓게 볼 수 있는 힘을 가질 수 있다고 생각해 이 자료를 정리해보았다.

HTTP 최근 트렌드에 대해 더 알고싶다면 파이프라인을 통해 하나의 세션에서 여러 요청을 보낼 수 있는HTTP2(SPDY), TCP 프로토콜보다 빠른 UDP 전송 계층 프로토콜 위에서 사용되는 HTTP3(QUIC)에 대해 살펴보면 좋을 거 같다.

Introduction to HTTP/2

QUIC - 위키백과, 우리 모두의 백과사전

참고자료

Hands-On RESTful API Design Patterns and Best Practices

HTTP(HyperText Transfer Protocol)의 특징

[HTTP] HTTP 특성(비연결성, 무상태)과 구성요소 그리고 Restful API

프런트엔드 개발자가 알아야하는 HTTP 프로토콜 Part 1

웹 서비스 캐시 똑똑하게 다루기

HTTP 조건부 요청 - HTTP | MDN

HTTP 메시지 - HTTP | MDN

Fetch 사용하기 - Web API | MDN

HTTP | MDN

profile
정보를 공유하겠습니다 😀

0개의 댓글