💡 본 포스트는 "그림으로 배우는 HTTP & Network Basic" 라는 책을 읽고 내 생각과 책 내용을 인용하여 작성했다.
HTTP 는 클라이언트와 서버간에 통신을 한다
HTTP 를 사용하여 2대의 컴퓨터간에 통신을 하는 경우, 어느 한 쪽은 반드시 클라이언트가 되고, 반대는 서버가 된다.
Request 와 Respons 를 교환하여 성립
HTTP 는 클라이언트로부터 요청(Request) 이 송신되며, 그 결과가 서버로부터 응답(Response) 로 되돌아온다. 즉, 반드시 클라이언트 측으로부터 통신이 시작된다. 서버 측은 요청을 받지 않고서는 응답을 송신하는 일은 없다.
HTTP Request
HTTP 요청 내부의 메시지 구조는 어떻게 구성될까? 요청(Request) 메시지는 메소드, URI, 프르토콜 버전, 요청 헤더 필드와 엔티티로 구성된다.
POST /form/entry HTTP/1.1
Host: hackr.ip
Connection: keep-alive
Content-Type: application/x-www-form-unlencoded
Content-Length: 16
name=msung99&age=20
- 메소드 : POST
- URI : /form/entry
- 프로토콜 버전 : HTTP/1.1
- 요청 헤더 필드 : Host, Connection. Content-Type, Content-Length 등장 부분
- 엔티티 : name 부분
HTTP Response
요청을 받은 서버는 요청 내용을 처리한 결과를 응답(Response) 로 클라이언트에게 되돌려준다. 응답 메시지는 보통 프로토콜 버전, 상태 코드 값, 해당 상태 코드를 설명한 구문, 응답 헤더와 응답 바디로 구성된다.
HTTP/1.1 200 OK
Date: Tue, 10 2020 06:50:15 GMT
Content-Length: 362
Content-Type: text/html
<html>
...
- HTTP 프로토콜 버전 : HTTP/1.1
- 상태코드 : 200
- 상태코드 설명 : OK
- 응답 헤더 필드 : Date, Content-Length, Content-Type 부분
- 응답 바디 : 헤더 필드와 한 줄의 공백을 두고 생긴 본문
HTTP 는 상태를 유지하지 않는 프로토콜
HTTP 는 상태를 유지하지 않는 stateless
프로토콜이다. HTTP 프로토콜은 이전에 보냈던 요청이나 이미 되돌려준 응답에 대해서는 전혀 기억하지 않는다. 이는 많은 데이터를 빠르고 확실하게 처리하는 범위성(scalability)
를 확보하기 위해서 복잡한 기억장치 구조없이 간단하게 설계된 것이다.
그러나 웹이 진화함에 따라, stateless 특성만으로는 처리하기 어려운 일이 증가하게 되었다. 예를들면 로그인했을 때, 다른 페이지로 이동했을 떄도 로그인 상태를 유지할 필요가 있다. 이를 위해서는 누가 어떤 요청을 보냈는지를 파악하기 위해 상태를 유지할 필요가 있다. HTTP/1.1 은 상태를 유지하지 않는 프로토콜이다. 그래서 상태를 유지하고 싶은 요구에 부응하기 위해서 쿠키(Cookie)
라는 기술이 도입되었다. 쿠키로 인해 HTTP 를 이용한 통신에서도 상태를 계속 관리할 수 있게 되었다.
Request URI 로 리소스를 식별
HTTP 는 URI 를 사용하여 인터넷 상의 리소스를 저장한다. 이 URI 가 있는 덕분에 인터넷 상의 어떤 장소에 있는 리소스도 호출할 수 있다. 클라이언트는 리소스를 호출할 떄 마다 요청을 송신할 때에 요청 내부에 URI 를 Request URI 라고 불리는 형식으로 포함해야 할 필요가 있다. Request URI 를 지정하는 방법에는 여러 종류가 있다.
- 모든 URI 를 Request URI 에 포함한다.
GET http://hackr.jp/index.html HTTP/1.1
- Host 헤더 필드에 네트워크 로케이션을 포함한다.
GET /index.htm HTTP/1.1
Host: hackr.ip
이것 외에도 특정 리소스가 아닌 서버 자신에게 요청을 송신하는 경우에는 Request URI 에 [*] 를 지정할 수 있다. 아래는 HTTP 서버가 지원하고 있는 메소드를 묻는 예이다.
OPTIONS * HTTP/1.1
서버에 임무를 부여하는 HTTP 메소드
HTTP/1.1 에서 사용할 수 있는 메소드에 대해 알아보자.
GET 메소드 (리소스 획득)
GET 메소드는 요청 URI 로 식별된 리소스를 가져올 수 있도록 요구한다. 가져올 리소스 내용은 지정된 리소스를 서버가 해석한 결과이다. 결국 리소스가 텍스트이면 그대로 반환하고, GGI 와 같은 프로그램이면 실행해서 출력된 내용을 돌려준다.
POST 메소드 (엔티티 전송)
POST 메소드는 엔티티 전송을 위해 사용된다. GET 으로 엔티티 전송은 가능하지만, 일반적으로 POST 를 사용한다. POST 는 GET 과 기능이 비슷하지만, Response 에 의한 엔티티를 획득하는 것 만이 목적은 아니다.
PUT 메소드 (파일 전송)
PUT 메소드는 파일을 전송하기 위해서 사용된다. FTP 프로토콜을 통한 파일 업로드와 같이, Request 중에 포함된 엔티티를 Request URI 로 지정한 곳에 저장하도록 요구한다.
파일을 전송하기 위해 사용된다. FTP 프로토콜을 통한 업로드와 같이 리퀘스트에 포함된 엔티티를 URI로 지정한 곳에 저장하도록 요구한다. 단, HTTP/1.1 PUT에는 인증 기능이 없어 누구나 파일을 업로드할 수 있게 되는 보안 문제가 발생한다. 따라서 일반적인 웹 사이트에서는 사용되지 않는다.
REST와 같은 설계 양식에서 사용되는 경우가 있다.
HEAD 메소드 (메시지 헤더 취득)
HEAD 메소드는 GET 과 같은 기능이지만 Message Body 는 돌려주지 않는다. URI 유효성과 리소스 갱신 시간을 확인하는 목적 등으로 사용된다.
DELETE 메소드 (파일 삭제)
DELETE 메소드는 파일을 삭제하기 위해 사용된다. PUT 메소드와는 반대로 동작하며, URI 로 지정된 리소스의 삭제를 요구한다. DELETE 자체에는 PUT 과 같이 인증 기능이 없기 떄문에 일반적인 웹 사이트에서는 사용되지 않는다.
REST와 같은 설계 양식에서 사용되는 경우가 있다.
OPTIONS 메소드 (제공하고 있는 메소드의 문의)
OPTIONS 매소드는 Request URI 로 지정한 리소스가 제공하고 있는 메소드를 조사하기 위해 사용된다.
이 외에도
TREACE
,CONNECT
메소드 등이 있지만, 향후 필요성을 느낄 때 동기 기반 학습을 진행하도록 한다.
메소드를 사용해서 지시를 내리다
Request URI 로 지정한 리소스에 요청을 보내는 경우는 메소드라는 명령이 있다. 메소드는 리로스에 어떠한 행동을 하기 원하는지를 지시하기 위해 존재한다. HTTP/1.0 과 HTTP/1.1 에서 제공하고 있는 메소드 종류는 아래와 같다.
- GET : 리소스 취득
- POST : 엔티티 바디 전송
- PUT : 파일 전송
- HEAD : 메시지 헤더 취득
- DELETE : 파일 삭제
- OPTIONS : 서포트하고 있는 메소드 문의
이 외의 다양한 메소드들에 대해선 앞서 말한 이유와 동일하게, 필요성을 느낄 떄 학습하도록 한다.
지속 연결로 접속량을 절약
HTTP 초기 버전에는 HTTP 통신을 한번 할 때마다 TCP 에 의해 연결과 종료를 할 필요가 있었다. 초기 당시의 통신에서는 작은 사이즈의 텍스트를 보내는 정도였기 떄문에, 한번 연결을 보낸 후 바로 연결을 종료해도 문제가 없었다. 그러나 HTTP 가 널리 보급되어감에 따라, 다량의 이미지를 포함한 문서가 늘어났다. 요청을 보낼 때 마다 매번 TCP 연결과 종료를 하게되는 과한 비용이 발생되어 통신량이 증가하게 되었다.
지속 연결
HTTP/1.1 과 일부 HTTP/1.0 에서는 TCP 연결 문제를 해결하기 위해 지속 연결(Persistent Connections)
이라는 방법을 고안했다. 지속 연결의 특징은 어느 한 쪽이 명시적으로 연결을 종료하지 않는 이상 TCP 연결을 계속 유지한다. 지속 연결을 하는 이점은 TCP 커넥션 연결과 종료를 반복하는 오버헤드를 줄여주기 떄문에 서버에 대한 부하가 줄어든다는 것이다. 또한, 오버헤드를 줄인만큼 HTTP 요청과 응답이 빠르게 완료되기 떄문에 웹 페이지를 빨리 표시할 수 있다.
파이프라인화
지속 연결은 여러 요청을 보낼 수 있도록 파이프라인화(HTTP Pipelining)
를 가능하게 한다. 파이프라인화에 의해서, 이전에는 요청 송신 후에 응답을 수신할 떄까지 기다린 뒤에 요청을 발행하던 것을, 응답을 기다리지 않고 바로 다음 요청을 보낼 수 있다. 이로인해, 여러 요청을 병행해서 전송하는 것이 가능해졌다. 따라서 일일이 응답을 기다릴 필요가 없어졌다.
쿠키를 사용한 상태관리
HTTP 는 Stateless 한 프로토콜이다. 따라서 과거에 교환했던 요청과 응답의 상태를 관리하지 않는다. 결국, 과거 상태를 근거로해서 요청을 처리한다는 것은 불가능하다. 예를들면, 인증이 필요한 웹 페이지에서 상태 관리를 하지 않는다면 인증을 마친 상태로 잊어버리기 때문에 새로운 페이지로 이동할 떄마다 재차 로그인 정보를 보내든지 요청마다 매개 변수가 추가 정보를 붙여서 로그인 상태를 관리해야한다.
stateless 라는 특징이 제공해주는 이점이 많지만, 이와 같은 상태 관리가 필요한 상황을 해결하기 위해 쿠키가 드장했다. 쿠키는 요청과 응답에 쿠키 정보를 추가해서 클라이언트의 상태를 파악하기 위해 시스템이다. 쿠키는 서버에서 응답으로 보내진 Set-Cookie
라는 헤더 필드에 의해 쿠키를 클라이언트에 보존하게 된다. 다음번에 클라이언트가 같은 서버로 요청을 보낼 때, 자동으로 쿠키 값을 넣어서 송신한다. 서버는 클라이언트가 보내온 쿠키를 확인해서 어느 클라이언트가 접속했는지 체크하고 서버 상의 기록을 확인해서 이전 상태를 알 수 있다.