
그림으로 배우는 HTTP & Network의 2장을 보고 정리한 글입니다.
HTTP는 클라이언트와 서버 간 통신을 한다
텍스트와 이미지 등과 같은 리소스를 필요하다고 요구하는 쪽은 클라이언트, 이러한 리소스를 제공하는 쪽은 서버가 됩니다.
HTTP를 사용하여 2대의 컴퓨터 간에 통신을 하는 경우, 통신을 할 때마다 반드시 한쪽은 클라이언트가 되고 다른 한쪽은 서버가 됩니다.
Request와 Response를 교환하여 성립
HTTP는 클라이언트로부터 요청(Request)이 송신되며, 그 결과가 서버로부터 응답(Response)하여 되돌아옵니다. 통신은 클라이언트로부터 시작됩니다. 서버는 요청을 수신하지 않으면 응답을 발생시키는 경우는 없습니다.
요청의 예시입니다.
GET /index.html HTTP /1.1
Host: www.google.com
클라이언트 측에서 HTTP 서버에 송신된 요청 내용입니다.
- "GET"은 서버에 요구하는 종류이며 메서드라고 불립니다
- "/index.html"은 요구 대상인 리소스를 나타내며 Request URI라고 합니다
- "HTTP/1.1"은 클라이언트 기능을 식별하기 위한 HTTP 버전 번호를 나타냅니다
즉, 해당 요청은 HTTP 서버 상에 있는 "/index.html"이라는 리소스가 필요하다는 요청입니다.
요청을 받은 서버는 요청 내용을 처리한 결과를 Response로 클라이언트에게 되돌려 줍니다.
HTTP/1.1 200 OK
Date: Tue, 18 Oct 2022 22:52:15 KST
Content-Length: 352
Content-Type: text/html
<html>
...
- "HTTP/1.1"은 서버의 HTTP 버전을 나타내고 있습니다
- "200 OK"는 클라이언트의 요청 결과를 나타내는 상태 코드입니다
- Date는 응답이 발생한 일시를 나타내며 헤더 필드라고 불리는 것 중 하나입니다
- 다음 빈 줄은 헤더의 끝을 표시하며 그 아래 부분은 바디라고 불리는 리소스 본체가 됩니다
상태를 유지하지 않는 프로토콜 HTTP
HTTP는 상태를 계속 유지하지 않는 무상태(stateless) 프로토콜입니다. HTTP 프로토콜 독자적으로, Request Response를 교환하는 동안에 상태(status)를 관리하지 않습니다. HTTP 프로토콜 레벨에서는 이전에 보냈던 Request나 이미 되돌려준 Response에 대해 전혀 기억하고 있지 않습니다.
HTTP에서는 Request를 보낼때마다 새로운 Response가 생성됩니다. 프로토콜로서 과거의 요청이나 응답 정보는 전혀 가지고 있지 않은데 이는 많은 데이터를 빠르고 확실하게 처리하는 범위성(scalability)을 확보하기 위해 이와 같이 설계되어 있습니다.
하지만 웹이 진화함에 따라 무상태 프로토콜의 특성만으로는 처리하기 어려운 일이 증가하게 됩니다. 예로 로그인을 하면 다른 페이지로 이동하더라도 로그인 상태를 유지할 필요가 있습니다. 이를 위해서는 누가 어떤 요청을 보냈는지 파악하기 위해 상태를 유지하여야 합니다.
HTTP1.1은 상태를 유지하지 않는 프로토콜입니다. 그래서 상태를 유지하고자 쿠키(Cookie)를 도입하게 됩니다.
리소스 식별 Request URI
HTTP는 URI(Uniform Resource Indeitifiers)를 사용하여 인터넷상의 리소스를 지정합니다. 이 URI로 인터넷상의 어떤 장소에 있는 리소스도 호출할 수 있습니다.
클라이언트는 리소스를 호출할 때마다 Request 안에 URI를 Request URI라고 불리는 형식으로 포함해야 합니다.
Request URI를 지정하는 방법에는 여러 종류가 있습니다.
모든 URI를 Request URI에 포함
GET http://www.google.com/index.html HTTP/1.1
Host 헤더 필드에 네트워크 로케이션을 포함
GET /index.html HTTP/1.1
Host: google.com
이 외에도 특정 리소스가 아닌 서버 자신에게 Request를 송신하는 경우에는 Request URI에 "*"를 지정할 수 있습니다.
OPTIONS * HTTP/1.1
서버에 임무를 부여하는 HTTP 메서드
HTTP/1.1에서 사용할 수 있는 메서드에 대해 알아보겠습니다.
GET: 리소스 획득
GET 메서드는 Request URI로 식별된 리소스를 가져오도록 요구합니다. 가져올 리소스는 지정된 리소스를 서버가 해석한 결과입니다.
리소스가 텍스트이면 그대로 반환하고 GGI와 같은 프로그램은 실행해서 출력된 내용을 반환합니다.
POST: 엔티티 전송
POST 메서드는 엔티티를 전송하기 위해 사용됩니다.
GET으로도 엔티티를 전송(쿼리 파라미터)할 수 있지만, 일반적으로 POST를 사용합니다.
PUT: 파일 전송
PUT 메서드는 파일을 전송하기 위해 사용됩니다. FTP(File Transfer Protocol)에 의한 파일 업로드와 같이 요청 중에 포함된 엔티티를 Request URI로 지정한 곳에 보존하도록 요구합니다.
HTTP/1.1 PUT 자체에는 인증 기능이 없어 보안 상의 문제로 일반적인 웹 사이트에서는 사용되지 않고 있습니다. 웹 애플리케이션 등에 의한 인증 기능과 연계하거나 REST(Representational State Transfer)와 같이 웹끼리 연계하는 설계 방식을 사용할 때 이용되기도 합니다.
HEAD: 메시지 헤더 취득
HEAD 메서드는 GET과 같은 기능이지만 메시지 바디는 돌려주지 않습니다.
URI 유효성과 리소스 갱신 시간을 확인하는 목적으로 사용됩니다.
DELETE: 파일 삭제
DELETE 메서드는 파일을 삭제하기 위해 사용됩니다. Request URI로 지정된 리소스의 삭제를 요구합니다.
HTTP/1.1의 DELETE 자체에는 PUT 메서드와 같이 인증 기능이 없기 때문에 일반적인 웹 사이트에서는 사용되고 있지 않습니다. PUT 메서드와 마찬가지로 인증 기능과 연계하거나 REST를 사용하는 경우에 이용되기도 합니다.
OPTIONS: 제공하고 있는 메서드의 문의
OPTIONS 메서드는 Request URI로 지정한 리소스가 제공하고 있는 메서드를 조사할 때 사용됩니다.
TRACE: 경로 조사
TRACE 메서드는 웹 서버에 접속하여 자신에게 통신을 되돌려 받는 루프백(loop-back)을 발생시킵니다.
요청을 보낼 때 "Max-Forwards" 라는 헤더 필드에 수치를 포함시켜 서버를 통과할 때마다 수치를 줄여갑니다. 수치가 0이 되면 요청을
마지막으로 수신한 곳에서 200 OK 리스폰스를 되돌려줍니다.
클라이언트는 TRACE 메서드를 사용하여 요청을 보낸 곳에 어떤 요청이 가공되어 있는지 등을 조사할 수 있습니다.
예시로 프록시 등을 중계하여 오리진 서버에 접속할 때 그 동작을 확인하기 위해 사용되고 있습니다.
하지만 TRACE 메서드는 크로스 사이트 트레이싱(XST)과 같은 공격을 받을 수 있는 보안 상의 문제가 있어 잘 사용되고 있지 않습니다.
CONNECT: 프록시에 터널링 요구
CONNECT 메서드는 프록시에 터널 접속 확립을 요함으로 TCP 통신을 터널링 시키기 위해 사용됩니다.
터널링 : 터널링은 통신 채널을 외부 공격으로부터 안전하게 보호해줍니다.
주로 SSL과 TLS 등의 프로토콜로 암호화된 것을 터널링 시키기 위해 사용되고 있습니다.
Request:
CONNECT proxy.google.com:8080 HTTP /1.1
Host: proxy.google.com
Response:
HTTP /1.1 200 OK (터널링 개시)
지속 연결
HTTP 초기 버전에서는 HTTP 통신을 할 때마다 TCP에 의해 연결과 종료를 했었습니다. 초기 당시의 통신에서는 작은 사이즈의 텍스트를 보내는 정도였기 때문에 문제가 되지 않았습니다. 그러나 HTTP가 널리 보급되면서 하나의 HTML에 다량의 이미지가 포함되어 있는 경우 이미지를 획득하기 위해서 여러 번의 요청을 송신하게 됩니다. 이렇게 요청을 보낼 때마다 매번 TCP 연결과 종료를 하게 되면 통신량이 늘어나게 됩니다.
HTTP/1.1과 일부 HTTP/1.0에서는 TCP 연결 문제를 해결하기 위해 지속 연결(Persistent Connections)이라는 방법을 고안하였습니다. 지속 연결은 어느 한쪽이 명시적으로 연결을 종료하지 않는 이상 TCP 연결을 계속 유지합니다.
지속 연결의 이점은 TCP 커넥션의 연결과 종료를 반복하는 오버헤드를 줄여주기 때문에 서버에 대한 부하가 적어집니다.
또한 오버헤드를 줄인만큼 HTTP 요청과 응답이 빠르게 완료되기 때문에 속도가 빨라지게 됩니다.
지속 연결은 HTTP/1.1에서는 표준 동작이지만 HTTP/1.0에서는 정식 사양이 아니었습니다. 일부 서버에서는 사양에 없는 기능을 구현하여 지속 연결을 사용하기도 했습니다.
파이프라인화(HTTP pipelining)
지속 연결은 여러 요청을 보낼 수 있도록 파이프라인화(HTTP pipelining)를 가능하게 합니다. 이전에는 요청을 송신한 후 응답을 수신할 때까지 기다린 뒤에 요청을 보냈지만 파이프라인화를 통해 응답을 기다리지 않고 바로 다음 요청을 보낼 수 있습니다.
예를 들면 HTML 한 페이지에 10 개의 이미지를 포함한 웹 페이즈를 요청한 경우에는 개별 연결보다 지속 연결이 빠르며 지속 연결보다는 파이프라인화 쪽이 빠릅니다. 이 차이는 요청의 수가 늘어날수록 많은 차이가 발생하게 됩니다.
쿠키를 사용한 상태 관리
HTTP는 무상태 프로토콜이기 때문에 과거에 발생했던 요청과 응답의 상태를 관리하지 않습니다. 인증이 필요한 웹 페이지에서 상태 관리를 하지 않기 때문에 인증을 마친 상태를 알 수 없어 페이지를 이동할 때마다 로그인 정보를 보내고, 요청마다 추가 정보를 통해 로그인 상태를 관리해야 하는 번거로움이 있습니다.
이러한 무상태 프로토콜에도 이점이 있습니다. 상태를 유지하지 않기 때문에 서버의 CPU나 메모리와 같은 리소스의 소비를 억제할 수 있습니다. 또한 단순한 프로토콜이기에 HTTP가 다양한 곳에서 사용될 수 있습니다.
무상태 프로토콜의 문제를 해결하기 위해 쿠키라는 시스템이 도입됩니다. 쿠키는 요청과 응답에 쿠키 정보를 추가하여 클라이언트의 상태를 파악하기 위한 시스템입니다. 서버에서 응답으로 보내진 Set-Cookie라는 헤더 필드에 의해 쿠키를 클라이언트에 보관하게 됩니다. 다음 번 클라이언트가 같은 서버로 요청을 보낼 때 자동으로 쿠키 값을 넣어 송신합니다. 서버는 클라이언트가 보내온 쿠키를 확인하여 어느 클라이언트가 접속했는지 체크하고 서버 상의 기록을 확인하여 이전 상태를 알 수 있습니다.
1. 클라이언트가 요청 송신
2. 서버는 쿠키를 발행하여 응답을 송신
3. 쿠키를 가지고 있는 상태의 클라이언트가 요청에 쿠키를 담아 요청 송신
4. 서버는 쿠키를 확인하여 해당 클라이언트의 이전 상태를 알고 상태에 따라 응답
'네트워크' 카테고리의 다른 글
[그림으로 배우는 HTTP & Network] 웹과 네트워크의 기본에 대해 알아보자 (2) | 2022.10.02 |
---|