blog logo
Published on

HTTP: 웹의 기초 - 1장 HTTP 개관

HTTP 완벽가이드 책 표지 이미지

들어가며

HTTP 완벽가이드 스터디를 진행하며 책 내용을 정리하고, 스터디 시간 중 토론한 내용을 블로그에 기록하려고 한다.

1.1 HTTP: 인터넷의 멀티미디어 배달부

수십억 개의 JPEG 이미지, HTML 페이지, 텍스트 파일, MPEG 동영상, WAV 음성 파일, 자바 애플릿 등이 하루도 쉬지 않고 인터넷을 항해한다. 이러한 정보들을 HTTP는 전세계 사람들에게 안전하게 전달해주는 역할을 한다. 정확히는 웹 브라우저로 옮겨준다.

사람들은 옆집에서부터, 또는 지구 반대편에서 오는 이러한 정보들을 어떻게 안전한지 알고 전달 받는 것일까? 이러한 신뢰성을 보장해주는 것이 바로 HTTP이다. HTTP는 신뢰성있는 데이터 전송 프로토콜을 사용하기 때문에 데이터가 꼬이거나 손상되는 걱정을 할 필요없이 안전을 보장한다.

그렇기 때문에 웹 서비스 사용자와 개발자 모두 HTTP 통신으로 인해 데이터가 왜곡되거나, 중복되거나, 파괴될 걱정을 하지 않아도 되는 것이다. 그래서 우리는 인터넷의 결함이나 약점에 대한 걱정 없이 애플리케이션 고유의 기능을 구현하는데 집중할 수 있다.

1.2 웹 클라이언트 서버

웹 컨텐츠는 웹 서버에 존재한다. 웹 서버는 HTTP 프로토콜로 의사소통하기 때문에 보통 HTTP 서버라고 불린다. 웹 브라우저는 서버에게 HTTP 객체를 요청하고 사용자의 화면에 보여준다.

1.3 리소스

웹 리소스는 웹 컨텐츠의 원천이다. 가장 단순한 웹 리소스는 웹 서버 파일 시스템의 정적 파일이다. 정적파일은 텍스트 파일, HTML 파일, JPEG 이미지 파일, 동영상 파일 등을 포함한다. 하지만 리소스는 반드시 정적 파일이어야 할 필요는 없다. 리소스는 요청에 따라 컨텐츠를 생산하는 프로그램이 될 수도 있다.

1.3.1 미디어 타입

인터넷에서는 수천 가지 데이터 타입을 다루기 때문에 HTTP는 웹에서 전송되는 객체 각각에 신중하게 MIME(Multipurpose Internet Mail Extentions, 다목적 인터넷 메일 확장) 타입이라는 데이터 포맷 라벨을 붙인다.

MIME은 전자메일 시스템 사이에서 각각 다른 메시지가 오갈 때 겪는 문제점을 해결하기 위해 설계되었다고 한다. 이 부분에서 잘 이루어졌기 때문에 HTTP에도 적용했다고 책에 나와있다.

웹 서버는 모든 HTTP 객체 데이터에 MIME 타입을 붙인다. 그리고 웹 브라우저는 서버로부터 객체를 돌려받을 때, 다룰 수 있는 객체인지 MIME 타입을 통해 확인한다.

MIME 타입 예시

  • HTML로 작성된 테스트 문서는 text/html
  • JPEG 이미지는 image/jpeg
HTTP MIME 타입 예시

1.3.2 URI

웹 서버 리소스는 각자 이름을 갖고 있기 때문에, 클라이언트는 관심있는 리소스를 지목할 수 있다. 그때 식별하는 역할이 바로 URI라고 할 수 있다. 그리고 URI에는 두가지가 있는데, 바로 URL과 URN이라는 것이다. URI에 포함되어 있는 하위 개념과도 같다.

1.3.3 URL

URI가 식별자의 역할을 한다면 URL은 그 중에서도 리소스에 대한 구체적인 위치를 서술하는 역할을 한다. 그리고 URL은 세 부분으로 이루어진 표준 포맷을 따른다.

  • URL의 첫번째 부분은 스킴(scheme)이라고 불리는데, 리소스에 접근하기 위해 사용하는 프로토콜이라고 생각하면 된다. 보통은 HTTP 프로토콜이다. (http://)
  • 두번째는 서버의 인터넷 주소를 제공한다. (ex: www.useonglee.dev)
  • 세번째는 웹 서버의 리소스를 가리킨다 (ex: /blog/http-개관)

오늘날의 대부분 URI는 URL이라고 한다.

1.3.4 URN

URN은 리소스의 위치에 영향 받지 않는 유일무이한 이름 역할을 한다. 예를 들어, 다음의 URN은 인터넷 표준 문서 'RFC 2141'가 어디에 있거나 상관없이 이것을 지칭하기 위해 사용할 수 있다.

하지만 책에서 URN은 아직 실험중이라고 한다. 전망은 밝다고 하지만 아직은 아닌 것 같다. 특별한 언급이 없다면 URI과 URL을 같은 의미로 봐도 좋을 것 같다.

1.4 트랜잭션

HTTP 트랜잭션은 클라이언트의 요청 명령과 서버의 응답 결과로 구성되어 있다. 그리고 이러한 상호작용은 HTTP 메시지라고 불리는 정형화된 데이터 덩어리를 이용해서 이루어진다.

1.4.1 메서드

HTTP는 HTTP 메서드라고 불리는 여러 가지 종류의 요청 명령을 지원한다. 모든 HTTP 요청 메시지는 한 개의 메서드를 갖는다.

  • GET: 서버에서 클라이언트로 지정한 리소스를 보내라.
  • PUT: 클라이언트에서 서버로 보낸 데이터를 지정한 이름의 리소스로 저장하라.
  • DELETE: 지정한 리소스를 서버에서 삭제하라.
  • POST: 클라이언트 데이터를 서버 게이트웨이 애플리케이션으로 보내라.
  • HEAD: 지정한 리소스에 대한 응답에서, HTTP 헤더 부분만 보내라.

1.4.3 웹 페이지는 여러 객체로 이루어질 수 있다

애플리케이션은 보통 하나의 작업을 수행하기 위해 여러 HTTP 트랜잭션을 수행한다. 예를 들어 웹브라우저는 웹 페이지를 가져올 때 대량의 HTTP 트랜잭션을 수행한다. 페이지 레이아웃의 뼈대인 HTML을 가져온 뒤, 웹 페이지에 필요한 이미지, 그래픽 조각, 자바 애플릿 등을 가져오기 위해 대량의 HTTP 트랜잭션이 수행되는 것이다. 그리고 주소가 다른 서버에서 리소스를 가져올 수도 있다.(CORS) 그래서 웹 페이지는 보통 하나의 리소스가 아닌 리소스의 모음이라고 할 수 있다.

1.5 메시지

HTTP 메시지는 단순한 줄 단위의 문자열이다. 이진 형식이 아닌 일반 텍스트이기 때문에 사람이 읽고 쓰기 쉽다. 그리고 웹 클라이언트에서 웹 서버로 보낸 HTTP 메시지를 요청 메시지라고 부른다. 반대로 서버에서 클라이언트는 응답 메시지다. 그리고 이외의 메시지는 없다.

HTTP GET 트랜잭션 예시

1.6 TCP 커넥션

1.6.1 TCP/IP

HTTP는 애플리케이션 계층 프로토콜이다. HTTP는 네트워크 통신의 핵심적인 세브사항에 대해서 신경쓰지 않는다. TCP는 다음을 제공한다.

  • 오류 없는 데이터 전송
  • 순서에 맞는 전달 (데이터는 언제나 보낸 순서대로 도착한다)
  • 조각나지 않는 데이터 스트림 (언제든 어떤 크기로든 보낼 수 있다)

TCP/IP는 각 네트워크와 하드웨어의 특성을 숨기고, 어떤 종류의 컴퓨터나 네트워크든 서로 신뢰성이 있는 의사소통을 하게 해 준다.

일단 TCP 커넥션이 맺어지면, 클라이언트와 서버 컴퓨터 간에 교환되는 메시지가 없어지거나, 손상되거나, 순서가 뒤바뀌어 수신되는 일은 결코 없다고 한다.

1.6.2 접속, IP 주소 그리고 포트번호

HTTP 서버의 IP 주소와 포트번호를 어떻게 알아낼 수 있을까? 바로 URL을 이용하면 된다. URL은 리소스에 대한 주소이기 때문에 URL에서 정보를 추출해서 알아내면 된다. 그러면 HTTP를 이용해서 서버의 단순한 HTML 리소스를 사용자에게 어떠한 과정을 통해 보여주는지 알아보자.

a. 웹 브라우저는 서버의 URL에서 호스트 명을 추출한다.
b. 웹 브라우저는 서버의 호스트 명을 IP로 변환한다.
c. 웹 브라우저는 URL에서 포트번호를 추출한다.
b. 웹 브라우저는 웹 서버와 TCP 커넥션을 맺는다.
e. 웹 브라우저는 서버에 HTTP 요청 보낸다.
f. 서버는 웹 브라우저에 HTTP 응답을 돌려준다.
g. 커넥션이 닫히면, 웹 브라우저는 문서를 보여준다.

1.7 프로토콜 버전

HTTP/0.9
HTTP/0.9는 오직 GET 메서드만 지원하고, MIME 타입이나 HTTP 헤더, 버전 번호는 지원하지 않는다. HTTP/0.9는 원래 간단한 HTML 객체를 받아 오기 위해 만들어진 것이다.

HTTP/1.0
HTTP/1.0은 버전 번호, HTTP 헤더, 추가 메서드, 멀티미디어 객체 처리를 추가했다.

HTTP/1.0+
오래 지속되는 'keep-alive' 커넥션, 가상 호스팅 지원, 프락시 연결 지원을 포함해 많은 기능이 공식적이진 않지만 사실상의 표준으로 HTTP에 추가되었다.

HTTP/1.1
1.1 버전은 HTTP 설계의 구조적 결함 교정, 두드러진 성능 최적화, 잘못된 기능 제거에 집중했다. 그리고 더 복잡해진 웹 애플리케이션과 배포를 지원한다. 현재의 HTTP는 HTTP/1.1 버전이다.

HTTP/2.0
HTTP/1.1 성능 문제를 개선하기 위해 구글의 SPDY 프로토콜을 기반으로 설계가 진행 중인 프로토콜이다.

1.8 웹의 구성요소

1.8.1 프락시

프락시는 클라이언트와 서버 사이에 위치하여, 클아이언트의 모든 HTTP 요청을 받아 서버에 전달한다. 사용자를 위한 프록시로 동작하며 프록시는 사용자를 대신해서 서버에 접근한다. 프록시는 주로 보안을 위해 사용한다. 즉, 모든 웹 트래픽 흐름 속에서 신뢰할 만한 중개자 역할을 한다. 또한 프록시는 요청과 응답을 필터링한다.

HTTP Proxy 예시

1.8.2 캐시

웹캐시와 캐시 프록시는 자신을 거쳐 가는 문서들 중 자주 찾는 것의 사본을 저장해 두는, 특별한 종류의 HTTP 프록시 서버다.

그래서 캐시 프록시는 성능 향상을 위해 자주 찾는 문서를 캐시에 저장해두고 필요할 때마다 더 빨리 문서를 다운받을 수 있다. 그래서 HTTP는 이러한 캐시를 효율적으로 사용해서 문서들을 최신 버전으로 유지하면서 동시에 프라이버시도 보호하기 위한 많은 기능을 정의한다.

HTTP Cache 예시

1.8.3 게이트웨이

게이트웨이는 주로 HTTP 트래픽을 다른 프로토콜로 변환하기 위해 사용된다. 게이트웨이는 스스로가 리소스를 갖고 있는 진짜 서버인 것처럼 요청을 다룬다. 클라이언트는 자신이 게이트웨이와 통신하고 있음을 알아채지 못할 것이다.

HTTP/FTP 게이트웨이는 FTP URI에 대한 HTTP 요청을 받아들인 뒤, FTP 프로토콜을 이용해 문서를 가져온다. 받아온 문서는 HTTP 메시지에 담겨 클라이언트에게 보낸다.

HTTP 게이트웨이 예시

1.8.4 터널

터널은 두 커넥션 사이에서 raw 데이터를 열어보지 않고 그대로 전달해주는 HTTP 애플리케이션이다. HTTP 터널은 주로 비 HTTP 데이터를 하나 이상의 HTTP 연결을 통해 그대로 전송해주기 위해 사용된다.

사용 예시로, 암호화된 SSL 트래픽을 HTTP 커넥션으로 전송함으로써 웹 트래픽만 허용하는 사내 방화벽을 통과시키는 것이 있다.

스터디 토론 내용

  1. HTTP가 왜 나왔을까?

나는 이 질문을 받았을 때 웹이 나온 이유부터 생각이 났다. 웹이 나온 이유는 단순히 정보를 주고 받기 위해서 탄생했으며, 이러한 정보를 조금 더 신뢰성있게 주고 받기 위해 나온것이 HTTP라고 생각했다.

같이 스터디하시는 분들도 비슷하게 생각했다. 토론 중 나왔던 이야기는 웹 상에서 정보를 서로 공유하려면 사람이 서로 이해할 수 있는 수준 기술의 필요성이 있다고 판단했고 그래서 HTTP가 나왔다는 의견도 있었다. OSI의 1, 2계층인 물리 계층과 데이터 링크 계층은 랜선과 0, 1로 이루어져있다. 그리고 이걸 상위 계층인 애플리케이션 계층에서 사람이 이해할 수 있는 수준의 데이터로 변경하면서 HTTP가 나온게 아닐까라는 토론을 했었다.


  1. MIME이 생긴 이유

이 질문에 대해서 나는 이렇게 대답했었다. 보통 헤더를 보고 데이터의 유형을 파악한다. 헤더의 content-type을 통해 데이터를 파악하기 때문에, 반대로 MIME 타입이 없으면 데이터의 유형을 파악하기 힘드니까 나온게 아닐까? 라는 생각을 했다.

하지만 같이 스터디하는 분의 의견을 듣고 설득 당했다.. 우리는 보통 리소스를 서버에 저장하고, 서버로 부터 리소스를 받아온다. text, image, video 등 보내는 측(서버)에서는 다 지원이 되지만, 받는 측에서는 어떤 타입은 되고 어떤 타입은 지원이 안되고 이런 경우가 있다. 이럴 때의 문제를 애초에 헤더에서 컷트할 수 있다면 더 좋지 않을까? 라는 의견이었고, 그래서 이 부분이 MIME 타입을 HTTP 객체 데이터에 붙인 이유라고 생각이 들었다.


  1. 트랜잭션에 대해서 어떻게 생각하는지?

트랜잭션의 본래 뜻은 거래이다. 그래서 HTTP 트랜잭션은 쉽게 클라이언트와 서버가 정보를 지불하고 원하는 것을 취득하는 거래 형식으로 이해를 했다. 즉, 클라이언트가 URI의 정보를 주면 서버는 그에 해당하는 리소스를 클라이언트에게 건내주는 것이다. 다른 스터디분은 데이터의 연산 과정이라고 생각했다고 한다. DB쪽에서 데이터를 불러오고 업데이트를 하는 것이 데이터 연산과 같다고 의견을 내주셨다.


  1. HTTP 메서드에 대해서 어떻게 생각하는지?

이건 영상을 추천 받았다. WAS, JVM 그리고 RESTful API

간단하게 초반 부분을 설명하면 초기의 웹 상태는 클라이언트의 요청과 응답에 의해서만 서버에 저장되어 있었다. html, image만 가져오는 형식이었다고 볼 수 있다. 하지만 현재는 스스로 html 화면단을 구성할 수 있는 기술들이 나왔다.

단순한 페이지의 정보만을 넘겨주기에는 웹 기술들(반응형 웹, 애니메이션 인터랙션 등)이 많이 발전했다. 뿐만아니라 웹에서 데이터 처리할 일이 많이 늘어나면서 현재는 데이터를 json 형태로 많이 주고 받게 되었다.

이러한 많은 형태의 json 데이터들을 편하게 처리하기 위해 HTTP 메서드가 나왔다고 생각하는데, 위의 짧지 않은 영상을 보면서 생각을 더 정리해 봐야겠다.


  1. REST API 꼭 필요할까?

얼마전 회사에서 REST API가 꼭 필요할까? 라는 질문을 받게 되었고, 그리고 get/post만으로도 API 명세서를 다 만들 수 있으며 엔드포인트로 API의 역할을 명확하게 만들어주는 것이 더 개발하는데 용이하지 않냐라는 질문을 받았다. 즉 다음과 같다.

  • POST /user HTTP/1.1
  • DELETE /user HTTP/1.1

두 개의 API 명세가 있을 때 POST API는 유저를 추가하는 API이고, DELETE API는 유저를 삭제하는 API이다. 그렇다면 API 명세서를 다음과 같이 만들자는 뜻이다.

  • POST /create/user HTTP/1.1
  • POST /delete/user HTTP/1.1

엔드포인트로 API의 역할을 구분해서 요청할 때도, 응답을 받을 때도 엔드포인트만으로 어떤 트랜잭션이 일어나는지 파악하자는 뜻이었다. 이 부분에 대해서 스터디분들과 이야기를 나눠보고 싶었고, 이 주제로 토론을 나누게 되었다.

팀원분들도 사이드 프로젝트를 하면서 GET/POST만으로 개발을 하신 경험이 있다고 했다. 다른 한 분께서 HTTP 1.1 RFC 문서(RFC-2616)에 나와 있듯이, 특정 메서드들은 멱등성을 보장해야 하기 때문에 옳은 선택일까? 라는 의견을 내주셨다.

사실 나는 메서드를 어떻게 활용할 것인가는 해당 팀 내의 팀원들이 REST API를 어떻게 받아들이는지, 프로젝트 상황이 어떠한지에 따라 다르다고 생각한다. 결국 개발은 팀원들과 같이 하는 것이기 때문에 이러한 방법들에 대해서는 정답이 없는 것 같다고 느껴진다. 우리 팀원들이 REST API에 대해 회의적이며, 엔드포인트로 명확하게 구분지어서 클라이언트와 서버가 트랜잭션하는 것이 더 좋다고 받아들이면 그것이 좋은 것이다.

실제로 최근부터 우리 회사 팀내에서 2번째 방법인 엔드포인트로 API를 구분지어서 사용하고 있다. 어플리케이션이 더 복잡해지고 API만 몇 십개, 몇 백개가 있는 상황에서 엔드포인트만으로 API의 역할을 파악할 수 있어서 개인적으로 개발하는데 용이하다고 생각하고 있다.


  1. 브라우저에서 url을 입력했을 때 사용자에게 리소스를 보여주기 까지의 과정과 상태코드를 연결지어서 이야기 해본다면?

이 부분은 면접이라고 생각하지 않고 이야기하듯이 말해보았다. 사용자가 브라우저 주소창에 url을 입력하면 브라우저는 서버에게 html 요청과 함께 응답을 받을텐데, 이때 만약 해당 url이 웹 캐싱이 되어있다면 거기서 문서를 가져오고, 그렇지 않다면 DNS 시스템을 따른다고 말했다. 현재는 알아보기 힘든 호스트 명으로 되어 있고, 이걸 DNS를 통해서 IP로 변환한다. 이후에 브라우저는 서버로부터 HTTP 응답을 받고, 문서를 보여준다. 하지만 이 대답에는 한가지 빼먹었다. 바로 TCP 커넥션이다.

DNS 시스템에 따라 IP 주소로 변환하고 클라이언트와 서버는 TCP 커넥션을 통해 요청과 응답을 주고 받는다. 이 부분에 대해서 정말 깊게 다룬 블로그를 추천 받았다! 👉 CLOSE_WAIT & TIME_WAIT 최종 분석 이 블로그에는 TCP 연결 과정과 TCP 커넥션을 다루는 방법까지 자세하게 나와있다. JAVA 코드를 아직 이해하지 못하고, 백엔드 지식이 부족한 나에게는 읽기 힘든 아티클이었지만 TCP 개념을 다시 잡기에는 좋은 글이었다.


이 다음부터는 1장이 아닌 2장 URL과 리소스에 대한 토론 내용이다. 2장에 대한 내용은 다루지 않았지만 토론 내용을 다뤄보려고 한다.

  1. URI와 URL의 차이는 무엇이며, 도대체 왜 나눴는가?

URI와 URL은 개념상으론 차이가 있어 보인다. 하지만 막상 개발을 하다보면 URI와 URL의 차이가 그래서 뭔지 헷갈릴 때가 있다. 왜냐하면 URL과 URN을 포함하고 있는 URI의 개념이 URL과 크게 차이가 없기 때문이다. 그럼에도 구분을 짓는다면 다음과 같다.

위에서 www.useonglee.dev/ 까지는 URI 그리고 URL 둘 다라고 말할 수 있다. 자원의 위치를 나타내고 있기 때문이다. 하지만 www.useonglee.dev/blog/HTTP-개관/index.html이 부분은 www.useonglee.dev/ 인 URL을 포함한 URI라고 말할 수 있다. 왜냐하면 자원의 식별자인 /blog/HTTP-개관/index.html을 포함하면서 웹 서버의 실제 위치를 나타내기 때문이다. 즉 자원의 위치까지는 URL과 URI 둘 다 가능하고, 자원의 식별자로부터 서버의 실제 위치를 나타내면 URI라고 말할 수 있는 것이다.

다른 예시로 www.useonglee.dev/blog/HTTP-개관/index 또는 www.useonglee.dev/blog/HTTP-개관은 URL이면서 URI라고 말할 수 있다. 실제 웹 서버의 주소를 나타내지 않고 자원의 위치만 나타내고 있기 때문이다.

스터디분이 질문했을 당시 도대체 왜 나눴는가에 대한 질문에서 명확하게 답변하지 못했다. 오늘날 URL 주소창에 /index.html 처럼 실제 서버의 주소를 적지 않기 때문이다. 그래서 책에서도 URL과 URI를 같은 개념으로 보고 설명하고 있다. 단지 나눈 이유를 묻는 다면 실제 서버 위치를 식별하는 용도와 자원의 위치를 식별하는 용도의 차이인데, 나누고 싶어서 나눴다기 보다는 용도에 따라 정의를 하다보니 URI안에서 URL, URN이 파생된거라고 생각하고 있다.

  1. 파라미터와 쿼리 스트링의 차이는?

사실 이 부분에 대해서 스터디원 모두 명확하게 대답을 하지 못해서 아쉬운 질문이었다. 쿼리 스트링은 개발하면서 정말 많이 활용했는데, 책에서 나오는 파라미터의 개념은 사용해보지 않아서 난감했다. 책에서 나오는 파라미터와 쿼리 스트링의 예시는 다음과 유사했다.

이 둘의 차이는 뭘까? 이 부분은 구글링을 통해 명확하게 알 수 있었다. 첫번째 주소인 파라미터 형식은 각 경로 조각(/blog, /index.html 등)마다 pages와 graphics라는 파라미터를 적용시킬 수 있다. 반면에 두번째 쿼리 스트링 형식은 한 URL에 한 번만 적용이 가능하며, 마지막 경로에 시작을 한다. 여러 경로 조각에 여러 파라미터를 사용할 수 있어서 유용해보이지만 실제로 나는 쿼리 스트링 형식만 써보았다. 이유를 찾아보니 여러 경로 조각에 파라미터를 적용시키는 방법은 오히려 복잡도가 증가할 수 있다는 것이다. 그렇다보니 많은 예시도 없었고, 나도 자연스럽게 쿼리 스트링으로 리소스 형식을 결정했던 것 같다.