HTTP에 대하여

Life is ninanino·2023년 4월 11일
1

오늘 또 하나 배웠다

목록 보기
12/17
post-thumbnail

"웹 개발자를 위한 웹을 지탱하는 기술"을 읽고 정리한 글입니다.


HTTP

HTTP는 TCP/IP를 베이스로 한 프로토콜이다. HTTP는 이름대로라면 하이퍼텍스트 전송용 프로토콜이지만 컴퓨터에서 다룰 수 있는 데이터라면 무엇이든 전송할 수 있다

TCP/IP 모델은 4계층으로 나누어져 있는데, 가장 밑단인 네트워크 인터페이스 계층부터 소개하겠다

네트워크 인터페이스 계층

가장 아래의 네트워크 인터페이스 계층은 물리적인 케이블이나 네트워크 어댑터에 해당한다

인터넷 계층

이 계층은 네트워크에서 데이터를 실제로 주고받는다. TCP/IP에서 IP가 여기에 해당된다. IP에서는 데이터의 기본적인 통신단위를 "패킷"이라고 부른다. 지정한 IP어드레스와 패킷 단위로 데이터를 주고받으면서 통신한다

참고로 패킷을 알려면 세그멘테이션, 세그먼트에 대해서 공부하면 도움이 된다

트랜스포트(전송) 계층

IP가 하지 않았던 데이터의 무결성을 보증한다. TCP가 해당한다
TCP는 목적지의 상대에 대해서 커넥션을 연결한다. 이 커넥션을 사용해 데이터의 누락을 체크하고, 데이터의 도달은 보증한다
TCP로 접속된 커넥션에서 전송하는 데이터가 어느 어플리케이션으로 전달될지 결정하는 것이 포트번호이다.

포트번호?
1~65535까지의 수치를 사용한다
HTTP는 디폴트로 80번 포트를 사용한다

애플리케이션(응용) 계층

구체적인 인터넷 애플리케이션, 메일이나 DNS, HTTP를 실현하는 계층이다
TCP로 프로그램을 만들 때는 소켓이라고 불리는 라이브러리를 사용하는 것이 일반적이다. 대부분의 프로그래밍 언어에서는 HTTP를 구현한 라이브러리가 준비되어 있기 때문에 소켓을 사용해서 HTTP를 독자적으로 구현할 일은 없지만, 웹 서비스와 API를 개발함에 있어서는 프레임워크의 세세한 동작과 설정, 파라미터 등이 프로토콜 수준에서 어떻게 동작하는지 파악해둘 필요가 있다

소켓?
소켓은 OS 커널에 구현되어있는 프로토콜 요소에 대한 추상화된 인터페이스.
네트워크에서의 데이터 교환을 추상화한 API이다
장치 파일의 일종으로 이해할 수 있음
일반 파일에 대한 개념이 대부분 적용됨


HTTP 1.1

HTTP 1.1은 0.9, 1.0을 거쳐서 만들어졌다.
HTTP 0.9에서는 헤더가 없었고 메서드는 GET 뿐이였다.
HTTP 1.0에서는 헤더가 도입되었고, GET 이외의 메서드가 추가되었다
그리고 1999년 RFC 2616이 발행되었다. 이것이 현재 HTTP의 스펙이다

RFC 2616 문서

공식 문서는 static한 텍스트 파일로 이루어져있다.(심지어 그림도 텍스트 형태로 그려져있다)
공부할때 참고하면 좋을 것 같다


Request - Response

클라이언트는 DNS를 사용해 호스트의 이름을 해석하고 그 결과로 얻은 IP 어드레스의 TCP 80번 포트에 접속한 후

GET /index.html HTTP/1.1
Host : .....
....
Keep-Alive : ...
Connection : keep-aliv

위와 같은 텍스트를 요청으로 전송한다

서버는 이 요청을 읽고 해석 한후

HTTP/1.1 200 OK
......
<html></html>

위와 같은 내용을 응답으로 보낸다.

클라이언트에선 어떤 일이 일어나고 있는 걸까?

클라이언트는 요청을 송신하고 응답받을 때
1. 요청 메시지 구축
2. 요청 메세지 송신
3. (응답이 돌아올 때까지 대기)
4. 응답 메세지 수신
5. 응답 메세지 해석
6. 클라이언트의 목적을 당성하기 위해 필요한 처리

의 과정을 거치게 된다.

서버는 무슨 일을 할까?

  1. (요청을 대기)
  2. 요청 메세지 수신
  3. 요청 메세지 해석
  4. 적절한 애플리케이션 프로그램으로 처리를 위임
  5. 애플리케이션 프로그램으로부터 결과를 취득
  6. 응답 메세지 구축
  7. 응답 메세지 송신

그리고 이 위 요청 메세지와 응답 메세지를 합쳐서 HTTP 메세지 라고 부른다.

요청 메세지 👤 ➡️

GET /index.html HTTP/1.1

요청 메세지의 첫번째 라인을 요청 라인(Request-Line)이라고 하며,
메서드(GET), 요청 URI(/index.html), 프로토콜 버전(HTTP/1.1)로 구성되어 있다.

요청 URI는 경로 이후의 문자열이 되거나 절대 URI가 된다. 요청 URI의 경로를 사용한 경우에는 Host 헤더가 필수적이지만, 절대 URI를 사용한 경우에는 Host헤더를 생략할 수 있다. HTTP 1.1의 경우는 요청 URI의 형식은 어느 쪽이든 상관없다.

프록시에 대한 요청인 경우는 요청 URI에 반드시 절대 URI를 사용해야한다.

요청 메세지의 둘째 줄 부터는 헤더가 이어진다. 헤더는 메세지의 메타 데이터이다. 하나의 메세지는 복수의 헤더를 가질 수 있고, 각 헤더는 "이름:값"의 구성을 하고있다.

Host: example.com:8080

헤더 뒤에 바디가 올 수 있다. 바디는 메세지를 나타내는 본질적인 정보가 들어간다. 예를 들어 리소스를 새로 작성하거나 갱신할 때는 요청의 바디부분에 리소스의 표현 자체가 들어간다

  1. 요청라인
  2. 헤더
  3. (바디) 올 수도 있고 안올 수도 있다

응답 메세지 ⬅️ 🖥️

http://example.com/test

요청이 성공하면 서버는 다음과 같은 응답을 클라이언트에게 보낸다

HTTP/1.1 200 OK
Content-Type: application/xhtml+xml; charset=utf-8

<html ~ > ... </html>

응답 메세지의 첫째 줄은 스테이터스 라인(Status-Line) 이라고 하며, 프로토콜 버전(HTTP/1.1), 스테이터스 코드(200), 텍스트 구문(OK)로 구성된다
스테이터스 코드는 요청의 결과를 프로그램으로 처리 가능한 수치 코드로 표현한다.

응답 메세지의 둘째 줄부터는 요청 메세지와 마찬가지로 헤더가 온다
위의 예제에선 Content-Type 헤더에서 HTML의 MIME(Multipurpose Internet Mail Extension) 미디어 타입(application/xhtml+xml)과 그 문자 인코딩 방식(utf-8)을 지정하고 있다

응답 메세지에는 바디도 포함되어 있다. 헤더와 바디는 빈 줄(헤더 맨 마지막 줄 끝에 연속하는 CRLF)로 구분된다. 이 예제에서는 바디에 HTML이 포함되어 있다

  1. 스테이터스 라인
  2. 헤더
  3. 바디

HTTP 메세지의 구성 요소

  1. 스타트라인
    요청 메세지의 경우는 요청라인, 응답 메세지의 경우에는 스테이터스 라인
  2. 헤더
    각 행의 줄 바꿈은 CRLF이다. 헤더의 종료는 빈 줄로 식별한다. 헤더는 생략 가능하다
  3. 바디
    텍스트 뿐만 아니라 바이너리 데이터도 들어갈 수 있고 바디도 생략이 가능하다

+---------------------+
| 스타트 라인(Start Line) |
|-----------------------|
|     헤더(Header)             |
|-----------------------|
|             빈 줄                    |
|-----------------------|
|        바디(Body)              |
+----------------------+

HTTP는 Stateless 즉, 상태가 없다. (무상태)
상태가 없다는 것은 서버가 클라이언트의 애플리케이션 상태를 보존하지 않는 다는 제약을 말한다

애플리케이션의 상태가 무엇일까?

예를 들어 우리가 커피를 사러갔을 때,
👻 : 커피 한잔 주세요
👩 : 어떤 커피 드릴까요?
👻 : 아메리카노 주세요
👩 : 차가운 걸로 드릴까요? 따뜻한 걸로 드릴까요?
👻 : 차가운 걸로 주세요
👩 : 더 필요하신건 없으세요?

위와 같은 상황을 Stateful이라고 한다. 즉 상태를 기억하고 있다.
그렇다면 Stateless 하다는 것은 뭘까?

👻 : 커피 한잔 주세요
👩 : 어떤 커피 드릴까요?
👻 : 아메리카노 주세요
👩 : 차가운 걸로 드릴까요? 따뜻한 걸로 드릴까요?
👻 : 차가운 걸로 주세요
👩 : 어떤걸 차가운 걸로 드릴까요?
👻 : 아메리카노요
👩 : 차가운 걸로 드릴까요? 따뜻한 걸로 드릴까요?
👻 : ?

점원은 내가 직전에 무엇을 말했는지 기억하지 못한다. 이것을 Stateless라고 한다

어플리케이션의 상태는 다른 이름으로 세션 상태라고도 한다.
시스템에 로그인하고 로그아웃 할때 까지 일련의 조작을 모아 "세션"이라고 부르는데, 이 일련의 조작 중의 상태는 애플리케이션의 상태를 말하는 것이므로, 애플리케이션과 세션 상태는 거의 동일한 의미이다

스테이트풀한 프로토콜은 FTP(파일 전송 프로토콜 (File Transfer Protocol))이다. FTP에서는 클라이언트가 FTP서버에 로그인해서 로그아웃할 때까지 그 클라이언트가 어느 디렉터리에 있는지와 같은 애플리케이션 상태를 서버가 관리한다. 그렇기 때문에 클라이언트는 디렉터리의 이동 등에서 상대 경로를 지정할 수 있다.
하지만 스테이트풀은 단점이 있다.
하나의 서버가 동시에 상대할 수 있는 클라이언트의 수에는 한계가 있다. 클라이언트가 증가하게되면 데이터를 동기화하는 오버헤드를 무시할 수 없다.

그렇다면 무상태가 좋은 거 아니야?

스테이트리스는 클라이언트가 요청 메세지에 필요한 정보를 모두 포함시킨다.
위에 예제를 보면 서버는 내 상태를 기억하지 못하는데? 🤔
-> 요청을 처리하는데 필요한 정보를 모두 포함시켜 메세지를 보내면 된다.
서버가 클라이언트의 애플리케이션 상태를 기억하는 대신에 클라이언트가 자신의 애플리케이션 상태를 기억하고 모든 요청을 자기 기술적 메세지로 송신한다.
그럼 서버는 상태를 기억할 필요가 없기 때문에 서버 시스템이 단순해 진다

하지만 이것도 결점이 있다....

송신할 데이터의 양이 많아지고, 인증 등 서버에 부하가 걸리는 처리를 반복한다. 스테이트풀에선 이전 메세지와 다른 부분만 보내면 충분했지만, 스테이트리스에서는 모든 정보를 재전송해야한다.

그럼 어쩌라고?

말했다시피 HTTP는 무상태 프로토콜이다. 이는 서버가 클라이언트의 상태를 저장하지 않는다는 것을 의미한다. 즉, 이전 요청과 상관없이 각각의 요청은 독립적으로 처리된다.

하지만 HTTP는 쿠키나 세션등을 통해 상태를 유지할 수 있다. 예를 들어, 쿠키를 사용하면 클라이언트 측에서 상태 정보를 저장하고 이 정보를 서버에 전송할 수 있다. 이를 통해 HTTP도 상태를 가질 수 있는 프로토콜이 된다.



출처 : 웹 개발자를 위한 웹을 지탱하는 기술

profile
백엔드 프로그래밍을 공부하고 있습니다. AWS, 클라우드 환경에 대해 관심이 많습니다.

0개의 댓글