HTTP에 대해서는 기본적으로 프로그래밍을 공부하다 보면 많이들 들어보았을 것이다. 하지만 이에 대해서 설명하라고 하면 자신있게 대답할 수 있을까? 이에 대한 나의 대답은 NO였고, 따라서 이번에 공부하면서 정리해보려 한다.
MDN 공식문서를 가장 기본적으로 참고하였다.
**HTTP를 이야기할 때, HTTPS를 빼놓을 수 없을 것이다. 이에 대해서는 블로그에 따로 정리해 두었으니 해당 링크를 참고하자.
HTTP란?
HyperText Transfer Protocol의 줄임말이다. 인터넷 상에서 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신규약이라는 의미이다.
웹브라우저(client)와 웹서버(server)즉, 서로 다른 컴퓨터 간에 컨텐츠를 교환하기 위한 규칙과 그 메시지가 HTTP다.
HTTP를 사전적인 의미로 풀어보면 위와 같다. 여기서 우리가 주목해야 할 부분은 Transfer Protocol 이다. HTTP가 무엇인지, 그 역할은 무엇인지 이 두 단어가 다 설명해주고 있다고 해도 무방하다. 즉 "웹 간에 something에 대해서 요청하고, 그 응답을 받아야 하는데 그 과정에서 어떤 방식으로 주고 받을지에 대한 규칙이 적힌 메시지" 인 것이다.
HTTP 기반 시스템의 구성요소
HTTP 각각의 개별적인 요청들은 서버로 보내지며, 서버는 요청을 처리하고 response라고 불리는 응답을 제공한다. 이 요청과 응답 사이에는 여러 개체들이 있다.
예를 들면 다양한 작업을 수행하는 게이트웨이 또는 캐시 역할을 하는 프록시 등이 있다.
실제로 브라우저와 요청을 처리하는 서버 사이에는 좀 더 많은 컴퓨터들이 존재한다(라우터, 모뎀 등) 웹의 계층적인 설계 덕분에, 이들은 네트워크와 전송 계층 내로 숨겨진다. HTTP은 애플리케이션 계층의 최상위에 있다고 볼 수 있다.
클라이언트: 사용자 에이전트
사용자 에이전트는 사용자를 대신하여 동작하는 모든 도구이다. 이 역할은 주로 브라우저에 의해 수행된다. 브라우저는 항상 요청을 보내는 개체이다.
웹 페이지를 표시하기 위해, 브라우저는 페이지의 HTML 문서를 가져오기 위한 요청을 전송한 뒤, 파일을 구문 분석하여 실행해야 할 스크립트 그리고 페이지 내 포함된 하위 리소스들(보통 이미지와 비디오)을 잘 표시하기 위한 레이아웃 정보(CSS)에 대응하는 추가적인 요청들을 가져온다. 브라우저는 HTTP 요청 내에서 지시 사항들을 변환하고 HTTP 응답을 해석하여 사용자에게 명확한 응답을 표시하는 역할을 한다.
웹 서버
통신 채널의 반대편에는 클라이언트에 의한 요청에 대한 문서를 제공하는 서버가 존재한다.
실제로 프로젝트 배포 시에 웹서버를 공부하며 정리해두었으므로, 더 자세한 사항은 아래의 링크를 참고하면 된다.
프록시
웹 브라우저와 서버 사이에서 수많은 컴퓨터와 머신이 HTTP 메시지를 이어 받고 전달한다. 이러한 컴퓨터/머신 중에서도 애플리케이션 계층에서 동작하는 것들을 일반적으로 프록시라고 한다. 프록시는 눈에 보이거나 그렇지 않을 수도 있으며(프록시를 통해 요청이 변경되거나 변경되지 않는 경우를 말함) 다양한 기능들을 수행할 수 있다.
- 캐싱 (캐시는 공개 또는 비공개가 될 수 있습니다 (예: 브라우저 캐시))
- 필터링 (바이러스 백신 스캔, 유해 컨텐츠 차단(자녀 보호) 기능)
- 로드 밸런싱 (여러 서버들이 서로 다른 요청을 처리하도록 허용)
- 인증 (다양한 리소스에 대한 접근 제어)
- 로깅 (이력 정보를 저장)
HTTP의 특징
1. 비연결성(Connectionless)
: 클라이언트와 서버가 한 번 연결을 맺은 후에, 요청과 응답이 마무리되면 연결을 끊어버리는 성질
1) 비연결성의 장점
HTTP는 인터넷 상에서 불특정 다수의 통신 환경을 기반으로 설계되었고, 만약 서버에서 다수의 클라이언트와 연결을 계속 유지해야 한다면, 이에 따른 많은 리소스가 발생하게 된다. 따라서 연결을 유지하기 위한 리소스를 줄이면 더 많은 연결을 할 수 있다.
2) 비연결성의 단점
서버는 클라이언트를 기억하고 있지 않으므로 동일한 클라이언트의 모든 요청에 대해, 매번 새로운 연결을 시도/해제의 과정을 거쳐야하므로 연결/해제에 대한 오버헤드가 발생한다.
-> 여기서 connection 에 대한 정보와 keep-alive가 등장하게 된다.(해당 블로그 참고)
비연결성의 단점인 오버헤드를 줄이기 위해 HTTP의 KeepAlive 속성이 등장했다.
General Header의 connection은 송신자가 연결에 대한 타임아웃과 요청 최대 개수를 어떻게 정했는지에 대해 알려준다. keep-alive는 단어 그대로, 이 연결을 영속적으로 유지한다는 의미이다. 이 영속성이라는 것은 한 번 통신하여 접속이 이루어 지면, 정의된 시간까지 접속이 없더라도 대기하는 구조이다. 즉 정의된 시간내에 access가 이루어진다면 계속 연결된 상태를 유지할 수 있다는 것이다.
이러한 방식이 왜 필요한 것일까?
만약에 연결이 유지되지 않는다면, 매번 socket(port)를 열어야 하고 이는 비용적인 측면에서 비효율적인 구조이다. 해서 keep Alive time out내에 client에서 request를 재 요청하면 socket(port)를 새로 여는 것이 아니라 이미 열려 있는 socket(port)에 전송하는 구조가 되고, socket을 열기위한 비용을 절약할 수 있다.
Keep-alive의 성능적 특징
A. 장점 : 커넥션을 맺고 끊는 데 작업이 없어졌기 때문에 시간이 단축된다는 것이다. 또한 서버와의 연결을 위한 자원도 절약할 수 있다.
B. 단점 : 바로 바쁜 서버 환경에서 Keep Alive 기능을 사용할 경우이다. 이는 모든 요청 마다 연결을 유지해야 하기 때문에 프로세스 수가 기하급수적으로 늘어나면 한 access의 MaxClient값을 초과하게 된다. 따라서 메모리를 많이 사용하게 되며 이는 곧 성능 저하의 원인이 된다. 즉 대량 접속 시 효율이 떨어지게 된다.
**Keep-alive에 대한 논의가 실제로 많이 이루어지고 있다는 사실을 공부하면서 깨달았다. 따라서 이에 대해서는 추가적으로 공부하고 정리해볼 예정이다.
2 무상태(Stateless)
: 클라이언트와 서버의 모든 통신은 독립적이라는 의미로 이해하는 것이 더 정확다고 생각한다.
이 말인 즉슨, 한번 로그인을 위한 통신을 했더라도 다음 통신에서는 이 로그인에 대해서 알지 못하므로, 유저의 로그인에 대한 정보를 유지시킬 방법을 생각해야 한다. 이러한 해결책으로 크게 쿠키와 세션, 그리고 JWT 토큰이 있다.
1) 쿠키
HTTP는 이러한 문제점을 해결하기 위해 브라우저 단에서 쿠키라는 것을 저장하여 서버가 클라이언트를 식별할 수 있도록 한다.
( HTTP 헤더 : set-cookie )
2) 세션
쿠키는 사용자 정보가 브라우저에 저장되기 때문에 공격자로부터 위변조의 가능성이 높아 보안에 취약하다. 이와 달리 세션은 브라우저가 아닌 서버단에서 사용자 정보를 저장하는 구조이다.
그런데 세션 정보도 중간에 탈취 당할 수 있기 때문에 보안에 완벽하다고 할 수 없다. 또한 세션을 사용하면 서버에 사용자 정보를 저장하므로, 서버의 메모리를 차지하게 되고, 만약 동시 접속자 수가 많은 서비스일 경우에는 서버 과부화의 원인이 된다.
*쿠키와 세션에 관해서는 블로그에 더 자세하게 정리할 예정
3) 토큰을 사용하는 OAuth, JWT
쿠키와 세션의 문제점들을 보완하기 위해 토큰( Token )기반의 인증 방식이 도입되었다. 토큰 기반의 인증 방식의 핵심은 보호할 데이터를 토큰으로 치환하여 원본 데이터 대신 토큰을 사용하는 기술. 그래서 중간에 공격자로부터 토큰이 탈취당하더라도 데이터에 대한 정보를 알 수 없으므로, 보안성을 높은 기술이라 할 수 있다. 대표적으로는 OAuth와 JWT이 있습니다.
이에 대해서 실제로 프로젝트를 진행할 때 우리는, 토큰을 활용하여 사용자 인증 방식을 활용하였고, 이에 대한 설명과 사용하는 방법은 하단의 블로그 글을 참고하면 된다.
JWT 토큰 사용하기(Python/Flask 환경 기준)
이는 우리가 웹브라우저 중에서 크롬을 킨 다음, 개발자도구를 열어서 network 탭을 킨다면, 아래의 화면을 통해 실제로 서버와 클라이언트 간에 통신하는 HTTP 메시지를 확인할 수 있다.
HTTP의 메시지와 그 구조에 대해서는 블로그에 따로 정리해 두었으니 해당 링크를 참고하자
HTTP를 이야기 하려면 빼놓을 수 없는 이야기가 바로 RestAPI 일 것이다. REST란, 웹 초기에 "웹을 무너뜨리지 않고 어떻게 HTTP 프로토콜을 발전 시킬 수 있을까?"에 대한 고민으로 시작된 아키텍쳐이다.
실제로 RestAPI에 대한 사용에 있어서는 복잡하며 나 또한 프로젝트를 진행하면서 다시 처음부터 공부했었다.(해당 글 참고)
그러나 아직도 이에 대해서 잘 이해했는지 확신이 서지 않으므로 이에 대해서는 좀 더 깊이 공부해 볼 예정이다.
HTTP 방식의 진화
1) HTTP 1.0
- status 코드 추가: 상태 코드 라인 또한 응답의 시작 부분에 붙어 전송되어, 브라우저가 요청에 대한 성공과 실패를 알 수 있게 되었다.
- 요청 결과에 대한 동작(특정 방법으로 그것의 로컬 캐시를 갱신하거나 사용하는 것과 같은)을 할 수 있게 되었다.
- 평이한 HTML 파일들 외에 다른 문서들을 전송하는 기능이 추가되었다(Content-Type 덕분에)
- 좁은 의미에서 공식적인 표준이 아니다.
- Method -> GET, POST, HEAD
2) HTTP 1.1 - 표준 프로토콜
- 커넥션이 재사용될 수 있게 하였다. 즉 connection : keep-alive 속성을 default로 두었다.
- 파이프라이닝을 추가하여, 첫번째 요청에 대한 응답이 완전히 전송되기 이전에 두번째 요청 전송을 가능하게 하였다.
- 청크된 응답 또한 지원된다. -> 동적인 컨텐츠를 위한 방식(전체의 큰 덩어리를 쪼개서 보내는 것이 chunk)
- 메서드에 OPTIONS, PUT, DELETE, TRACE 가 추가
-> HTTP 1.1 의 문제점
- 연결당 하나의 요청과 응답을 처리하기 때문에 동시 전송 문제와 다수의 리소스를 처리하기에 속도와 성능 이슈가 존재
- HOL(Head Of Line) Blocking (특정 응답 지연)
- -> HTTP/1.1의 사양상의 제한으로 클라이언트의 리퀘스트의 순서와 서버의 응답순서는 동기화해야 됨
- RTT(Round Trip TIme) 증가 (양방향 지연)
- 헤더가 크다 (특히 쿠키 때문)-> 사용자가 방문한 웹페이지는 다수의 http 요청이 발생하게 되는데 이 경우 매 요청시 마다 중복된 헤더 값을 전송하게 되며 각 도메인에 설정된 쿠키 정보도 매 요청시 마다 헤더에 포함되어 전송
- -> http/1.1의 헤더에는 많은 메타 정보들이 저장되어 있음.
3) HTTP 2.0
- Multiplexed Streams (여러 요청을 동시 처리)
- HOL (Head Of Line) 미발생
- Stream Prioritization (요청 리소스간 의존관계를 설정)
- Header 정보를 HPACK으로 압축
- -> 중복되는 헤더값을 색인값으로 처리
- Client 요청 없이 리소스 Push
- HTTP 1.1과 호환
- 페이지 로딩 속도 향상
'SW Engineering > Dev' 카테고리의 다른 글
What is HTTPS? (0) | 2021.01.17 |
---|---|
HTTP의 구조에 대해 이해하기(특히 Header 구조 파악하기) (0) | 2021.01.17 |
Django vs Flask / React (0) | 2021.01.04 |
소셜 로그인_네이티브 앱키/javascript키/Rest API키 차이점 (0) | 2020.11.27 |
소셜로그인기능 구현(2)_github social 로그인 (0) | 2020.11.27 |