겨울방학에 개인 프로젝트로 채팅기능을 가지고 있는 앱을 만들어 볼 계획이다.
채팅은 실시간 양방향 통신이 가능하도록 구현해야 할 것이다.
이 전까지는, REST api를 이용하여, 즉 HTTP method를 통해 resource를 처리하도록 아키텍쳐를 설계하였다. 통상적으로 클라이언트가 요청을 보내는 경우에만 서버가 응답하는 "단방향 통신"을 중심으로 모든 것을 구현하였다.
그러다 문뜩, 채팅같은 실시간으로 양방향 통신은 어떻게 이루어지는 것인지, 내부 서버에서는 이것이 어떤 원리로 동작하는지 궁금하게 되었고, 이번에 직접 만들어보고 싶었다.
채팅에서는 통상적으로 웹 소켓 통신을 이용하는데, 이는 데이터 송수신을 동시에 처리할 수 있다고 한다. 즉, 클라이언트와 서버가 서로에게 원할 때 데이터를 주고 받을 수 있다고 한다.
그래서 웹 소켓에 대해 알아보고 공부해서 채팅 서비스를 구현해보기 이전에 간단하게 HTTP프로토콜에 대해 정리하고 복습해보려한다.
HTTP(Hypertext Transfer Protocol)는 인터넷상에서 데이터를 주고 받기 위해서 서버/클라이언트 모델을 따르는 프로토콜이다.
서버/클라이언트 모델?
: (보통 웹브라우저인) 수신자 측에 의해 요청이 초기화되는 프로토콜을 의미
애플리케이션 레벨의 프로토콜로 TCP/IP위에서 작동한다.
HTTP는 어떤 종류의 데이터든지 전송할 수 있도록 설계되어 있다. 이 데이터의 예로는 HTML문서, 이미지, 동영상, 오디오, 텍스트 문서 등 여러 종류가 있다.
하이퍼텍스트 기반으로(Hypertext) 데이터를 전송하겠다(Transfer) ==> 링크 기반으로 데이터에 접속하겠다는 의미이다.
클라이언트에서 요청(request)을 보내면 서버는 요청을 처리해서 응답(response)을 한다.
URL 분석 및 접속
웹 브라우저는 URL을 분석해 IP주소와 포트(웹서버는 보통 표준포트인 80번을 이용)를 이용해 서버와 TCP/IP 연결을 요청한다.
Request Header 전송
브라우저에서 요청 파일명 등이 기술된 헤더를 전송한다.
Request Body 전송
필요한 경우에, 로그인 폼에 입력한 데이터나 첨부 파일 등의 추가적인 데이터를 전송한다.
Response Header 해석
서버에서 헤더를 수신하고 응답 상태등을 확인하며, Body부분의 Content-type 등을 확인한다.
Response Body 해석
바디가 있는 경우에, 서버에서 수신한 Body를 헤더에 기술된 Content-Type에 따라서, text/html인 경우에 HTML을 렌더링하고, image/jpeg인 경우에는 그림을 띄우는 등 적절히 해석한다.
HTTP는 Connectionless 방식으로 작동한다.
서버에 연결하고, 요청해서 응답을 받으면 연결을 끊어버린다.
그리고 기본적으로는 자원 하나에 대해서 하나의 연결을 만든다.
장점:
불특정 다수를 대상으로 하는 서비스에 적합한 방식이다. 수십만명이 웹 서비스를 사용하더라도 접속유지는 최소한으로 할 수 있기 때문에, 더 많은 유저의 요청을 처리할 수 있다.
단점:
연결을 끊어버리기 때문에, 클라이언트의 이전 상태를 알 수가 없다. 이러한 HTTP의 특징을 stateless라고 하는데, Connectless로 부터 파생되는 특징이라고 할 수 있다. 클라이언트의 이전 상태 정보를 알 수 없게 되면, 웹 서비스를 하는데 당장에 문제가 생긴다. 클라이언트가 과거에 로그인을 성공하더라도 로그 정보를 유지할 수가 없다. HTTP는 cookie를 이용해서 이 문제를 해결하고 있다.
Cookie(쿠키)란?
HTTP를 기반으로 하는 웹 서비스는 connectless방식으로 이전의 상태정보를 유지할 수 없다. 결국 클라이언트의 상태정보를 정보조각 형태로 서버와 클라이언트(웹 브라우저)에 남기는 방식으로 문제를 해결한다. 이 정보조각을 cookie(쿠키)라고 한다. 서버는 cookie를 이용해서 세션정보를 관리한다.
즉, HTTP은 상태가 없지만, 세션은 있다는 것이다.
HTTP는 상태를 저장하지 않아, 동일한 연결 상에서 연속하여 전달된 두 개의 요청 사이에는 연결고리가 없다. 비회원의 장바구니처럼, 일관된 바식으로 사용자가 페이지와 상호작용하기를 원할 때 문제가 된다. 하지만, HTTP의 핵심은 상태가 없는 것이지만, HTTP의 쿠키는 상태가 있는 세션을 만들도록 해준다.
(쿠키는 클라이언트쪽에서 저장하고 있으며, 서버에 요청할 때, 이 쿠키를 서버에 보냄)
헤더 확장성을 사용하여, 동일한 상태를 공유하기 위해 각각의 요청들에 세션을 만들도록 HTTP 쿠키가 추가된다.
HTTP는 사람이 읽을 수 있으며 간단하게 고안되었다. 심지어 HTTP/2가 다소 더 복잡해졌지만 여전히 HTTP 메세지를 프레임별로 캡슐화하여 간결함을 유지하였다. HTTP 메시지들은 사람이 읽고 이해할 수 있어, 테스트하기 쉽고 초심자의 진입장벽을 낮췄다.
HTTP 헤더는 HTTP를 확장하고 실험하기 쉽게 만들어졌다. 클라이언트와 서버가 새로운 헤더의 시맨틱에 대해 간단한 합의만 한다면, 언제든지 새로운 기능을 추가할 수 있습니다.
HTTP의 확장 가능한 특성은 수년 간에 걸쳐 웹의 점점 더 많은 기능들을 제어하도록 허용되어 왔다. 캐시 혹은 인증 메서드는 HTTP에 초기부터 제어해왔던 기능이며, 반면에 origin 제약사항을 완화시키는 조치는 2010년에 들어서 추가되었다.
다음은 HTTP 사용하여 제어 가능한 일반적인 기능 목록이다.
캐시
HTTP로 문서가 캐시되는 방식을 제어할 수 있다. 서버는 캐시 대상과 기간을 프록시와 클라이언트에 지시할 수 있고 클라이언트는 저장된 문서를 무시하라고 중간 캐시 프록시에게 지시할 수 있다.
origin 제약사항을 완화하기
스누핑과 다른 프라이버시 침해를 막기 위해, 브라우저는 웹 사이트 간의 엄격한 분리를 강제한다. 동일한 origin으로부터 온 페이지만이 웹 페이지의 전체 정보에 접근할 수 있다. 그런 제약 사항은 서버에 부담이 되지만, HTTP 헤더를 통해 그것을 완화시킬 수 있다. 그런 덕분에 문서는 다른 도메인으로부터 전달된 정보를 패치워크할 수 있다(그렇게 하려면 어떤 경우에 보안과 관련된 사항이 있을 수도 있다).
인증
어떤 페이지들은 보호되어 오로지 특정 사용자만이 그것에 접근할 수도 있다. 기본 인증은 HTTP를 통해 WWW-Authenticate (en-US) 또는 유사한 헤더를 사용해 제공되거나, HTTP 쿠키를 사용해 특정 세션을 설정하여 이루어질 수도 있다.
프록시와 터널링 (en-US)
서버 혹은 클라이언트 혹은 그 둘 모두는 종종 인트라넷에 위치하며 다른 개체들에게 그들의 실제 주소를 숨기기도 한다. HTTP 요청은 네트워크 장벽을 가로지르기 위해 프록시를 통해 나가게 된다. 모든 프록시가 HTTP 프록시는 아니다. 예를 들면 SOCKS 프로토콜은 좀 더 저수준에서 동작한다. FTP와 같은 다른 프로토콜도 이 프록시를 통해 처리될 수 있다.
세션
쿠키 사용은 서버 상태를 요청과 연결하도록 해준다. 이것은 HTTP가 기본적으로 상태없는 프로토콜임에도 세션을 만들어주는 계기가 되었다.
클라이언트는 URI를 이용하여 자원의 위치를 찾는다.
URI는 HTTP와는 독립된 다른 체계다.
HTTP는 전송 프로토콜이고,
URI는 자원의 위치를 알려주기 위한 프로토콜이다.
URI는 World Wide Web상에서 접근하고자 하는 자원의 위치를 나타내기 위해서 사용한다. 이때, 자원은 html문서, 이미지, 동영상, 오디오 등 모든 것이 될 수 있다.
웹페이지의 위치를 나타내기 위해서 사용하는 https://www.naver.com/index.html이라는 URI가 있다고 예로 들어보자.
이를 분석하면 다음과 같다.
이렇게 "프로토콜", "위치", "자원명"으로 어디에 있던지 자원에 접근할 수 있다.
메서드는 요청의 종류를 서버에게 알려주기 위해서 사용한다.
각 용도에 맞는 메서드가 준비돼 있음에도 GET과 POST만으로도 모든 종류의 요청을 표현할 수 있다.
명시적으로 메서드를 사용하지 않아도 웹 서비스 개발에 큰 문제는 없지만, Restful API 서버의 경우에는 GET, POST, DELETE, PUT을 명시적으로 구분한다.
자원의 위치 뿐만 아니라 자원에 할 일 까지 명확히 명시할 수 있기 때문에, Open API 서버를 만들기 위해서 널리 사용한다.
HTTP Request형식은 다음과 같다.
웹 브라우저는 웹 서버에 데이터를 "요청"하는 "클라이언트 프로그램" 이다. 요청은 서버가 인식할 수 있는 약속된 형식 (HTTP 형식)을 따라야 한다.
요청 데이터는 "HEADER"와 "BODY"로 구성된다.
필수 요소로 요청의 제일 처음에 와야 하는 3개의 필드가 있다.
요청 메서드 : GET, PUT, POST, PUSH, OPTIONS 등의 요청 방식이 온다.
요청 URI : 요청하는 자원의 위치를 명시한다.
HTTP 프로토콜 버전 : 웹 브라우저가 사용하는 프로토콜 버전이다.
그 외의 키값
Host : 요청을 보내는 Host
(예) www.test101.com
Content-Type : 요청에 바디가 있는 경우 그 파일 포맷
(예) Content-Type: application/json
Cookie : 웹 브라우저에 저장된 쿠키들
User-Agent : 클라이언트의 정보, 이를 통해 사용하는 브라우저 감지