
- #http
HTTP - 기본 흐름 정리하기
Prolip
2025-01-17
http가 어떻게 흘러가는지 기본 흐름과 url의 6가지 구조, 응답, 요청에 대해 알아보기
HTTP 흐름
curl http://localhost:3000/ch01.txt -v * Host localhost:3000 was resolved. * IPv6: ::1 * IPv4: 127.0.0.1 * Trying [::1]:3000... * Connected to localhost (::1) port 3000 > GET /ch01.txt HTTP/1.1 > Host: localhost:3000 > User-Agent: curl/8.9.1 > Accept: */* > < HTTP/1.1 200 OK < Date: Mon, 17 Feb 2025 07:30:36 GMT < Connection: keep-alive < Keep-Alive: timeout=5 < Transfer-Encoding: chunked < HTTP Lecture 1. Basic 1.1 HTTP Start 1.2 HTTP Message* Connection #0 to host localhost left intact
- TCP 연결 수립 (3-Way-Handshake
- 클라이언트가 localhost 대상으로 3000번 포트에 연결하기 위한 tcp 패킷을 보낸다. ⇒ 서버가 연결을 수락하는 패킷을 다시 클라이언트로 보낸다. ⇒ 클라이언트는 다시 이 패킷을 확인했다고 서버로 보내는데 이를 통해 TCP 연결이 수립되며 3-Way-Handshake라고 한다.
- 전화로 비유하면, cURL 클라이언트가 전화기라고 생각해보자. 그럼 클라이언트는 이 전화기에 전화하고 싶은 대상인 localhost:3000라는 전화번호를 입력하고, 이제 통화 버튼을 누르면 3-Way-Handshake가 시작되는 것이다.
- 이후 서버에서 전화를 받고 연결이 되면 통화를 시작할 준비가 되는 것이다.
- 위의 코드 블록을 보면
Trying [::1]:3000…
라는 요청을 시도하는 패킷을 보내고 있다. 이후Connected to localhost (::1) port 3000
라는 TCP 연결이 수립된 상태를 다시 나타내게 된다.
- HTTP 메세지 전송
- 이제 서버와 클라이언트가 TCP로 연결되면 클라이언트는 HTTP로 메세지를 전송할 수 있다. 하지만 아무렇게나 보낼 수는 없고, 정해진 HTTP 규격에 맞게 보내야만 한다. 그래야 서로 이 메세지를 제대로 이해할 수 있기 때문이다.
- cURL 메세지의 오른쪽 화살표로 나타난 부분이 이 규격에 맞는 메세지 형태다. GET 요청주소 cURL 클라이언트가 사용한 HTTP 버전이 나타나고, 오리진 주소인 Host, 자신의 요청 환경인 User-Agent 등이 나타난다.
- 마지막 빈 줄로 메세지의 끝을 나타낸다. 즉, 전화라면 전화가 연결된 후 ‘여보세요’라고 말한 셈이다.
- HTTP 메세지 수신
- 이제 서버가 클라이언트가 보낸 메세지를 받아 다시 클라이언트로 메세지를 수신하는데, 이 메세지도 HTTP 규격에 맞게 보내진다. 왼쪽 화살표로 나타난 부분이 서버에서 보낸 메세지를 의미한다.
- 마지막 빈 줄 이후로 서버가 보낸 본문이 담겨있다.
- 이제 이 부분은 ‘여보세요’ 이후로 대답한 셈이다.
- TCP 연결 종료
- 이후 클라이언트가 서버로부터 응답 메세지를 받으면 TCP 연결이 끊어지는데 이건 전화를 끊은 셈이다.
URL
클라이언트가 요청을 보낼 때 대상이 되는 것이 바로 URL인데, Uniform Resource Locator의 약자로 인터넷 상의 파일의 위치를 지정하는 방식으로 이해하자.
URL을 크게 프로토콜, 도메인, 포트, 경로, 쿼리 문자열, 앵커로 구성된다.
프로토콜://도메인:포트/경로?쿼리문자열#앵커
-
프로토콜: http://도메인:포트/경로?쿼리문자열#앵커
- URL은 프로토콜로 시작한다. 이 프로토콜은 URL의 종류를 결정하는 역할을 하는데, http로 시작한다면 웹 문서를 식별하는 URL이 된다. 클릭하면 보통 웹 브라우저가 실행되며 해당하는 페이지를 볼 수 있다.
- http만 있는 것이 아닌, 메일 전송에 사용되는 mailto 프로토콜, 전화에 사용되는 tel 등 여러 프로토콜이 존재한다.
-
도메인: http://localhost:포트/경로?쿼리문자열#앵커
- 도메인은 요청하는 웹 서버를 나타낸다. 도메인의 IP를 알려주는 서버인 Domain Name System에 이 도메인 이름을 전달하면 해당하는 서버의 IP 주소를 얻을 수 있다. 물론 IP 주소를 바로 사용해도 된다. 그럼 DNS를 통하지 않고 바로 서버로 접속할 수 있다.
- google.com, naver.com 등이 이 도메인에 해당된다고 볼 수 있다.
-
포트: http://localhost**:3000**/경로?쿼리문자열#앵커
- 포트는 웹 서버의 리소스에 접근하는 데 사용되는 기술적인 게이트를 나타낸다. IP로 접속한 서버는 여러 포트가 존재하는데, 배로 비유하자면 항해하다 육지에 들어갈 때 여러 항구 중 하나를 선택해야 한다. 이것과 비슷하다고 볼 수 있다.
-
경로: http//localhost:3000**/ch01.txt**?쿼리문자열#앵커
- 여기까지 도메인과 포트 번호로 서버의 특정 프로그램에 접속했다. 하지만 URL은 이 프로그램이 제공하는 파일까지 가르킬 수 있어야 한다.
- 그래야 클라이언트가 그 파일을 받아 화면에 표시할 수 있기 때문이다. 여기서 서버가 제공하는 파일의 위치가 바로 이 경로인 path다. 예제의 경우 ch01.txt, ch02.txt가 이 경로에 해당하는 것이다.
- 상황에 따라 서버의 실제 경로가 아닐 수도 있는데, 이건 서버 구현에 따라 다르다. 웹 초기의 경우 웹 서버의 실제 파일 위치를 나타냈으나 요즘에는 대부분 물리적 실체가 없는 웹 서버가 추상적으로 처리한다.
-
쿼리 문자열: http//localhost:3000/ch01.txt**?query=name**#앵커
- URL이 특정 파일까지 식별했다면 파일 외 추가로 서버에 정보를 전달하는 경우가 있을 수 있다. 이 때 쿼리 문자열을 사용하는데, 일정한 형식을 갖추고 있다.
- ? 기호로 시작해 equal 기호를 통해 키/값 형태로 나타낸다. 만약 정렬에 대한 정보를 제공한다면 ?sort=best 형태로 전달될 것이다.
- 하나만 제공하는 것이 아닌 여러 개를 전달하는 상황이 있을 수 있는데 이 경우엔 뒤에 & 기호를 사용해 여러 개를 전달할 수도 있다. ?sort=best&query=name
-
앵커: http://localhost:3000/ch01.txt?query=name**#title**
- 앵커는 리소스 내부의 일종의 책갈피 역할을 하는데, 브라우저에 해당 책갈피 지점의 콘텐츠를 표시하도록 지시한다.
<div id='title1'>Title1</div> <div id='title2'>Title2</div> <div id='title3'>Title3</div>
- 예를 들어 위의 경우에서 앵커를 #title3으로 설정했다면, 브라우저가 이 HTML 문서의 id가 title3인 영역으로 스크롤한다. 이 프래그먼트 식별자라고도 하는 앵커 뒤의 부분은 요청과 함께 서버로 전송되지 않는다는 점을 주목하자.
요청
이제 URL로 자원의 식별자를 정하면 그 대상으로 메세지를 보낼 수 있다.
> GET /ch01.txt HTTP/1.1 > Host: localhost:3000 > User-Agent: curl/8.9.1 > Accept: */* >
이 요청을 다시 보자면, 클라이언트에서 curl 명령어 뒤에 URL을 입력해 요청을 보내고 있다.
클라이언트에서 서버로 전달하는 메세지를 요청, 즉 리퀘스트라고 부른다. curl 명령어의 결과의 오른쪽 화살표 영역이 요청 영역이다.
GET /ch01.txt HTTP/1.1를 살펴보자면, 클라이언트와 서버 간의 요청 방식을 정의하는 메서드로 GET 요청을 사용함을 알 수 있다. 뒤의 경로 부분은 파일의 식별자이고 마지막은 클라이언트와 서버 간에 어떤 버전의 HTTP를 사용할지 클라이언트가 버전을 제안하고 있는 것이다.
이렇게 제안한 정보를 기반으로 서버는 어떤 HTTP 버전으로 응답할지 결정하게 된다.
이후 아래 영역부터 요청 헤더로 볼 수 있다. 요청 헤더는 콜론을 기준으로 왼쪽이 key, 오른쪽이 value에 해당한다.
- Host: localhost:3000
- 이 영역은 호스트라는 요청 헤더로 요청을 보낼 호스트와 포트 정보를 보내는데, 서버의 위치와 어떤 포트를 사용할지 명시한 것이다.
- User-Agent: curl/8.9.1
- 클라이언트 정보를 나타내는 헤더로 curl 클라이언트를 사용했기 때문에 curl/8.9.1로 나타난다. 만약 브라우저를 사용했다면, 브라우저 정보가 나타날 것이다.
- Accept: /
- 클라이언트가 어떤 컨텐츠 타입을 받을지 표시하는 헤더 영역으로 와일드 카드 형태로 어떤 컨텐츠 타입이던 모두 받겠다는 의미다.
전화로 생각해보자면, User-Agent 헤더는 전화 건 사람, 1,2 번 줄에서 어떤 사람을 찾고 있는지 나타낸다고 보면 되겠다
응답
이제 서버는 클라이언트가 보낸 요청을 처리하게 된다.
< HTTP/1.1 200 OK < Date: Mon, 17 Feb 2025 07:30:36 GMT < Connection: keep-alive < Keep-Alive: timeout=5 < Transfer-Encoding: chunked < HTTP Lecture 1. Basic 1.1 HTTP Start 1.2 HTTP Message* Connection #0 to host localhost left intact
응답은 상태 코드, 응답 헤더, 그리고 응답 본문으로 구성되는데,
상태코드는 첫 번째 줄에 위치한다. 클라이언트가 보낸 요청 메세지에 사용할 프로토콜 버전이 있었다. 서버에도 이 버전을 사용할 수 있는 경우에 같은 버전을 표시해 서로의 버전을 맞추게 된다.
이후 상태코드를 표시해 요청을 받은 서버가 처리 결과를 알려주는데, 정수로 표기된 상태 코드와 함께 사람이 읽을 수 있는 문자로도 표시하게 된다.
크게 다섯 가지로 분류한다.
- 10X
- 100번대는 정보성 응답으로 대표적으로 프로토콜 전환 요청을 승인할 때 사용하는 101번이 있다.
- 20X
- 200번대는 성공을 의미하는 상태코드로 요청에 성공하면 200번을 응답한다. 자원을 생성한 경우 201, 요청은 성공했으나 응답 본문이 없는 경우 204를 응답하게 된다.
- 30X
- 300번대는 리다이렉션을 의미한다. 301인 경우 요청한 리소스 URI가 영구적으로 이동했음을 의미하며 바뀐 주소를 응답 헤더에 표시하게 된다.
- 302는 임시적으로 이동했음을 의미하며, 304는 클라이언트가 캐시해둔 리소스를 사용해도 된다고 본문을 비워서 응답할 수 있다.
- 40X
- 400번대는 클라이언트 오류로 요청에 문제가 있어 서버가 처리하지 못한 경우 사용하는 상태 코드다.
- 대표적으로 400 Bad Request로 잘못된 요청으로 인해 서버가 이해할 수 없을 때, 400으로 응답한다.
- 인증이 필요한 경우 401, 존재하지 않는 페이지를 요청한 경우 404로 응답하게 된다.
- 50X
- 500번대는 서버의 처리 과정에서 생긴 오류로 요청 자체는 문제가 없지만 서버의 어떤 이유로 요청을 처리하지 못했다는 의미다.
- 대표적으로 500 Internal Server Error로 서버에서 예상하지 못한 에러가 발생했을 때, 500번 상태 코드를 응답하게 된다.
- 서버가 다운되어 요청을 처리할 수 없을 때 503, 타임아웃이 발생한 경우 504를 응답하기도 한다.
이제 응답 헤더의 다른 영역을 살펴보자면, 요청 형식과 똑같이 콜론을 기반으로 key/value 형식으로 이루어져있음을 알 수 있다.
- Date: Mon, 17 Feb 2025 07:30:36 GMT
- Date 응답 헤더는 서버가 응답한 시간을 값으로 실어 보낸다.
- Connection: keep-alive
- 아래의 Connection: keep-alive 헤더는 TCP 연결을 일정 기간 유지하기 위해 쓰이는 헤더로, 원래 클라이언트와 서버 간의 요청/응답 사이에는 항상 TCP 연결을 수립하기 위한 3-Way-Handshake가 필요하다.
- 하지만 이 과정에 시간이 오래 걸리기 때문에 이 요청 헤더로 연결을 일정 기간 유지하겠다고 명시하는 것이다.
- Keep-Alive: timeout=5
- 바로 아래 이 다시 보낼 수 있는 제한 시간을 나타내는 Keep-Alive: timeout=5 헤더로 5초간 유지하겠다고 명시하는 것이다.

타입스크립트 - OOP와 타입스크립트
