<목차>
- HTTP를 가능하게 해주는 인터넷 네트워크
- IP
- TCP, UDP
- PORT
- DNS
- URI와 웹브라우저 요청 흐름
- URI
- 웹브라우저 요청 흐름
- HTTP 기본
- 클라이언트 서버
- Stateful, Stateless
- 비연결성
- HTTP 메세지
- HTTP 메서드
- GET
- POST
- PUT
- PATCH
- DELETE
- 그외
- HTTP 상태코드
- 1XX - 요청 처리중
- 2xx - 성공
- 3xx - 리다이렉션
- 4xx - 클라이언트 오류
- 5xx - 서버오류
- HTTP 헤더
- 일반헤더
- 표현
- 콘텐츠 협상
- 전송방식
- 인증
- 쿠키
- 캐시와 조건부 요청
- 캐시 기본동작
- 검증헤더와 조건부 요청
- 프록시캐시
- 캐시 무효화
- 일반헤더
HTTP통신에 대해 좀더 깊게 공부해보고싶다는 갈망이 있던 차에 HTTP A to Z 라는 주제를 뽑게 되었습니다.
이번 세미나를 위해 인프런에서 언젠가 들어봐야겠다고 벼르고 있던 ‘모든 개발자를 위한 HTTP 웹 기본 지식’ 이라는 강의를 들었고, 이 강의의 내용을 정리해서 전달 해보려고 합니다.
1. HTTP를 가능하게 해주는 인터넷 네트워크
두 컴퓨터가 바로 옆에있다면 그냥 케이블로 연결해서 데이터를 넘겨줄 수 있습니다.
하지만 한국에서 미국에 있는 친구에게 메세지를 보내려고 한다면 어떻게 해야할까요?
이때 우리는 당연하게 인터넷을 통해 메세지를 보내게 됩니다.
하지만 인터넷이 어떻게 동작하는지 알고 계신가요? 우리가 공부할 HTTP를 공부하기위해 HTTP가 동작하는 기반인 인터넷에 대해 간략하게 알아보도록 하겠습니다.
HTTP(Hyper Text Transfer Protocol)는 하이퍼텍스트 전송 프로토콜이라는 의미인데,
(Hyper Text는 HTML문서를 의미합니다. 웹의 근간이 되는 정보를 담은 문서이지요.)
어딘가로 전송을 할 수 있으려면 일단 연결이 되어있어야 합니다.
연결이 되어있기 때문에, 데이터를 주고 받을 수 있는 것이지요.
이 연결이 바로 인터넷 입니다.
인터넷 이전에 네트워크가 있습니다. 네트워크란 서로 통신이 가능하도록 장치 사이를 연결하는 것을 의미하는데 유선으로 혹은 무선으로 기기가 연결 된 것을 말합니다. 이렇게 네트워크로 연결된 기기들 사이에는 뭔가를 주고 받을 수 있게 됩니다.
하지만 같은 네트워크에 속한 단말들간에만 소통이 가능하고, 다른네트워크의 단말과는 소통이 불가능 합니다.
그래서 각 네트워크들을 서로 연결해서 다른 네트워크에 있더라고 통신하여 정보나 자원을 공유할 수 있게 된 것이 인터넷 입니다.
이렇게 네트워크가 나뉘는 이유는 물리적인 한계가 있기 때문입니다.
간단히 예를들면 네트워크망은 규모와 거리에 따라 LAN, MAN,WAN으로 나눈다고 하는데, 한 네트워크로 연결하는 규모에 한계가 있기 때문에 네트워크 와 네트워크를 나눠서 연결하고 그 네트워크들을 연결하는 방식을 사용하게 된 것 이지요.
인터넷(Internet)은 여러 통신망을 하나로 연결한다는 의미의 ‘인터 네트워크(inter-network)’라는 말에서 시작된 것으로, 여러개의 네트워크가 연결된 것을 의미합니다. 전 세계 컴퓨터들이 하나로 연결하는 거대한 컴퓨터 통신망으로 연결 되었다는 것이지요.
하지만 이렇게 연결만 한다고 뭔가를 주고받을 수 있는것은 아닙니다.
한국어만 할 수 있는 사람이 중국어만 쓰는 사람을 만났다면 서로 대화가 불가능 할 것입니다.
서로 한국어로 대화를 하기로 협의해서 한국어로 소통 하기로 했다고 가정 해보겠습니다.
그런데 이번에는 한국어만 하는 사람이 일본어만 사용하는 사람과 대화해야할 일이 생겼습니다.
이 두사람은 서로 대화가 불가능할것이고 또다시 어떤 협의를 통해 대화할 수 있게 될거에요.
100가지 언어가 있다면 우리는 100가지 소통 방법을 정립해야 할 겁니다.
그래서 전세계가 연결되어 소통하는 인터넷에서는 통신방식을 통일할 필요가 생기게 되었고,
이를 위해서 인터넷에서는 TCP/IP라는 하나의 통신 프로토콜(통신 규칙)만을 사용합니다.
인터넷을 사용해서 출발지에서 목적지까지 도달하기 위해서는 험난한 과정을 거쳐야 합니다.
한번에 목적지로 갈 수 있는것이아니라 중간의 수많은 노드들을 거쳐 목적지에 도달할 수 있기 때문이에요.
중간에 해저광케이블을 거쳐갈수도 있고, 인공위성을 거쳐야 할수도 있는데요, 이렇게 많은 노드를 거쳐도 정확히 목적지에 도착할 수 있는 것은 앞서말한 인터넷 통신규약인 TCP/IP덕분입니다.
그럼 이제부터 IP를 알아가보도록 하겠습니다.
a. IP(인터넷 프로토콜)
복잡한 인터넷망에서 hello world라는 메세지를 미국친구에게 보내려면 은 일단 주소가 있어야 가능합니다.
IP주소는 인터넷 프로토콜을 사용하는 네트워크에 연결된 모든 장치에 할당된 번호로, 컴퓨터의 고유한 주소입니다.
IP주소는 요청을 보내는 나도, 메세지를 받을 친구도 IP주소를 부여받아야 합니다.
편지를 보내려면 보낸이와 받는사람의 주소를 다 필요한 것 처럼 말이죠.
인터넷 프로토콜(IP)은 지정한 IP주소에 데이터를 전달할때, '패킷'이라는 통신단위로 데이터를 전달합니다.
IP패킷이라는 규칙이 있는데, 전송데이터 밖에 나의IP, 목적지IP 를 적은 IP패킷을 만드는 것입니다.
위의 이미지 처럼 전송할 데이터를 IP패킷으로 싸서 전송합니다.
이제 이 IP패킷을 인터넷 망에 던집니다.
앞에서 말했듯 클라이언트에서 서버로 한번에 이동을 할 수 있는것은 아니고, 그 사이에있는 노드들을 거쳐서 가게 됩니다.
그러면 IP프로토콜에 의해, 이 규약을 따르고있는 서버들은 출발지는 뭐고 목적지는 뭐라는것을 다 이해하고 있을 것입니다.
인터넷망의 노드들이 서로 패킷을 던지면서 목적지IP와 일치하는 노드를 찾게 되고. 이렇게 목적지IP까지 도달하게 됩니다.
패킷이 성공적으로 전달되면 친구도 출발지IP, 목적지IP를 담은 패킷을 나에게 다시 전송할 수 있습니다.
다시 인터넷망의 노드들을 거쳐 목적지IP와 일치하는 컴퓨터에 도착하게 되겠지요.
인터넷망은 복잡하기 때문에 요청할때랑 응답할때 중간에 거쳐가는 노드들이 다를수도 있습니다.
보내는곳과 목적지 주소를 알게되어 데이터를 주고 받을수는 있게 되었지만, 복잡한 인터넷 망에서 패킷이 오고가는 과정에서 발생할 수 있는 문제들이 있습니다.
- 비연결성 : 친구PC가 꺼져있어도 나는 알수가 없기 때문에 그냥 보내게 됩니다.
- 비신뢰성 : 전송중에 패킷이 중간에서 사라지거나, 패킷을 여러개 보냈을때 도착순서를 컨트롤 할 수 없습니다.
- 프로그램 구분 불가 : 한컴퓨터에서 음악도듣고 게임도 하면, 어떤 프로그램에서 던진 패킷인지 IP만으로는 구분할 수가 없습니다.
클라이언트는 대상서버가 살아있는지 알수없어도 그냥 패킷을 보내기 때문에. 전송이 잘 되었는지도 알 수 없습니다.
중간에 광케이블이 갑자기 끊어져서 패킷이 소실되더라도 알수가 없을 것입니다.
또, 패킷의 용량이 엄청 큰 경우도 있을텐데요.
메세지가 보통 1500byte넘으면 끊어서 패킷을 나눠 보냅니다.
이렇게 끊어 보내는 패킷의 도착순서를 보장할수가 없습니다. 순서가 달라지면 보낸 의도와 다른 결과물이 될 수 있을 것입니다.
출발지IP와 목적지 IP만 명시하는 IP프로토콜만으로는 이문제를 해결할 수 없었고. 그래서 등장한 것이 TCP 프로토콜입니다.
패킷이 중간에 사라지고 순서가 꼬이는 문제를 TCP가 해결해주는데, 간단히 말하면 IP의 위에 IP에는 포함되지 않은 추가정보들을 씌워서 보완해 주는 것입니다.
b-1. TCP의 특징
TCP는 Transmission (전파, 전송) Control Protocol. 즉, 전송제어프로토콜로 전송을 어떻게할지 제어합니다.
TCP에는 3가지 특징이 있습니다.
1. 연결지향 :3 way handshake
데이터가 전송되기 전에 클라이언트와 서버간의 연결을 성립하는 과정이 이루어 지게 됩니다. 이 과정을 통해 꺼져있는 서버로 요청을 보내는 일은 방지 됩니다. 서로의 존재를 확인하는 절차를 수행한 후 정식 데이터를 교환하기 위한 통신 선로를 개설하게 됩니다.
통신선로 하나를 만들기 위해서 3번의 데이터 교환이 이루어지기 때문에 3way handshake라고 합니다.
- 클라가 서버에 syn(연결시켜줘)
- 서버가 클라에 syn(나도 연결시켜줘) + ack(연결 허락)
- 클라가 서버에 ack(연결 허락)
- 데이터 전송 (요즘은 마지막 3번 ack보낼때 데이터도 전송해서 속도를 개선한다고 합니다)
2. 데이터 전달을 보증
데이터 전송하면 서버가 데이터 잘 받았다고 응답 해줍니다. 응답이 안오면 뭔가 문제가생겼다고 인지 할 수 있게 됩니다.
3. 순서 보장
크기가 커서 잘라서 보내졌을떼, 1,2,3순서로 보냈을때 보낸 순서대로 도착하지 않으면, 순서가 어긋난 곳 부터 다시 보내라고 요청합니다.
예를들어 1, 2, 3 순서로 보냈을때 1번 다음 3번이 오면 다 버리고 ‘패킷2부터 다시보내’ 라고 서버에서 클라에 다시 요청합니다.
물론 서버에서 최적화도 가능한데, 드라이버에 전송받은 데이터를 모아두었다가 1,3,2면 1,2,3으로 쓰거나 하는 처리를 할 수 있습니다.
하지만 기본적으로는 서버가 클라에 다시 요청하도록 합니다.
이런 순서보장이 가능할 수 있는 것은 TCP 데이터에 전송 제어, 순서 ,검증 정보가 들어있기 때문입니다.
이렇게 TCP/IP프로토콜을 지켜서 만들어진 패킷을 살펴보면,
IP패킷에는 출발지IP, 목적지 IP가 적혀져 있고, TCP 세그먼트에는 출발지와 목적지 PORT번호, 전송제어, 순서 ,검증번호 등이 적혀져 있습니다.
패킷은 Package(수화물)+Bucket(덩어리)의 합성어 입니다. 택배같은 수화물 덩어리 라고 생각하면 될 것입니다.
b-2. UDP 프로토콜
UDP는 TCP랑 같은 계층에있는 프로토콜로 TCP의 대안으로 사용될 수 있지만, TCP와는 달리 많은 기능이 없는 하얀 도화지같은 상태의 프로토콜 입니다.
3way handshake도 없고 순서보장도 없는 상태입니다. IP랑똑같은데 'Port' + '체크섬'이 추가된 형태이죠.
(체크섬은 데이터를 보내는 쪽에서 전송할 데이터를 16비트 워드 단위로 구분하고 1의 보수를 취하고 그 합에대한 결과를 전송하면, 수신하는 쪽에서 같은 합을 해보아서 오류를 검출하는 방식이라고 한다. 즉 간단한 데이터 검증 방식이 추가된 프로토콜이라는 것이다.)
그렇다면 UDP이런 빈 도화지같은 UDP를 왜쓰는걸까 라는 의문이 드는데, UDP에도 장점이 있습니다.
TCP는 다 좋지만 이미 많은 기능이 있기 때문에 데이터양도 크고 전송 속도를 빠르게하기가 어렵습니다.
더 최적화하고싶어도 한계가 있는 구조입니다. 반면 UDP는 아무것도 안되어 있기 때문에 애플리케이션 레벨에서 만들어 낼 수 있어 각광받고 있다고 합니다.
TCP프로토콜이 거의 90%점유하고 있지만, 최근 나온 HTTP/3에서 웹브라우저에서 HTTP통신을 할때 TCP/IP 핸드쉐이킹까지 줄어보자 해서 UDP프로토콜을 사용하고 있습니다.
c. 포트
Port는 항구 라는 뜻 입니다.
PC에서 웹브라우저 ,게임 ,화상통화를 동시에 하고 있으면 한개의 PC가 여러개의 서버와 통신하게 됩니다.
패킷이 내 IP로 날아오면 어떤 애플리케이션에서 필요한 패킷인지 알 수가 없습니다.
보낼때도 마찬가지로, 어떤 애플리케이션이 보낸 요청인지 식별할 수 가 없습니다.
그래서 하나의 컴퓨터에서 실행중인 서로 다른 프로그램을 구별하기 위한 포트를 사용하게 되었습니다.
IP가 아파트라면 Port는 몇동 몇호인지에 대한 정보인 것이지요.
그래서 TCP/IP패킷에는 출발지IP,목적지IP 외에도 출발지 포트와 목적지 포트도 포함되어 있습니다.
클라에서 패킷보낼때 출발지 IP, 출발지 Port도 보내기때문에 서버에서 응답할때도 IP, PORT가 같이 올수있게 됩니다.
PORT번호로는 0~65535까지 사용할 수 있습니다.
하지만 0~1023은 잘 알려진 포트로 사용하지 않는게 좋습니다.
<유명한 포트 예시>
20,21 : FTP
23 : Telnet
80 : HTTP
443 : HTTPS
잘 알고있다시피 HTTP는 80, HTTPS는443 포트를 기본으로 사용하고있어서, 포트번호를 생략하는것도 가능합니다.
<네트워크 통신 계층>
유명한 OSI 7계층은 네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것입니다.
OSI 7계층말고도 TCP/IP 4계층이라는 것도 있습니다.
OSI 7계층과 TCP/IP 4계층의 차이 아래 이미지를 보면 알 수 있듯이 TCP/IP 4계층 모델은 OSI 7계층이 좀 더 논리적으로 병합하여 축약된 것으로 알 수 있습니다.
즉, OSI 7계층이 네트워크 전송의 데이터 표준을 정립했다면, TCP/IP 4계층은 이를 실제로 사용하는 인터넷 표준인 셈이라고 합니다.
우리가 채팅프로그램으로 미국친구에게 Hello world라는 메세지를 넘기는 과정을 프로토콜 계층에 적용해서 생각해보겠습니다.
채팅앱에서 메세지를 생성하고,
브라우저의 소켓라이브러리를 통해 서 OS계층에 Hello, world! 메세지를 넘깁니다.
OS계층에서 Hello, world! 메세지에 TCP정보를 하나 씌우고(PORT,순서 ,검증 정보 ),
밑에 한칸 더 내려가면 IP계층에서 TCP정보 밖에 IP 관련정보를 하나 더 씌우게 됩니다.(목적지 IP, 출발지 IP ..)
이렇게 IP패킷이 생성되게 됩니다. 이 IP패킷이 실제 네트워크 인터페이스를 통해서(LAN카드를 통해서) 인터넷으로 나가게 됩니다.
d. DNS (Domain Name System)
IP주소는 숫자로 되어있어 기억하기가 어렵습니다. 예) 100.100.100.1
또, IP는 변경될 수도 있는데. 그러면 바뀐 IP를 다시 알아야 요청을 보낼 수 있습니다.
도메인 네임 시스템은 중간에서 전화번호부같은 서버를 제공해주는것인데, 영문/한글 주소로 IP주소를 찾을수 있도록 해줍니다.
google.com에 들어갈래 라고 DNS서버에 요청하면 응답으로 IP를 알려주고, 그러면 그 IP를 갖고 서버에 요청하면 됩니다.
만약 IP가 바뀌게 되면 DNS의 IP만 바뀌면 되고, 클라이언트는 바뀐 IP를 신경쓰지 않고 DNS에 알고 있는 글로된 주소로 요청해서 변경된 IP주소를 응답받고, 그 IP로 서버에 요청을 보낼 수 있습니다.
2. URI와 웹브라우저 요청 흐름
HTTP는 요청 대상을 "리소스"라고 하고, 리소스는 문서, 사진, 동영상 그 어떤것이든 될 수 있습니다.
각 리소스는 식별을 위해 HTTP 전체에서 사용되는 URI로 식별됩니다.
a. URI, URL, URN
URI뿐만 아니라 URL, URN을 많이 들어보긴 했는데 이들의 관계와 뜻은 뭘까요?
URI(Uniform Resource Identifier)은 리소스를 식별하는 통합된 방법 이라는 뜻입니다.
식별은 사전적으로 "무엇인지 알아보거나, (다른 대상과) 그 차이를 알아 구별하는 것" 이라는 의미입니다.
사람을 주민번호로 누가 누구인지 구분할 수 있듯이, 어떤 자원이 그것이라는것을 구별할 수 있도록 나타내는 방식 이라고 할 수 있겠습니다.
URI가 어떤자원이 그것이라고 구별할 수 있는 방식이라면, URL과 URN은 URI의 형식들 입니다.
URL(Uniform Resource Locator)은 '리소스의 위치'라는 뜻으로 자원을 구별 위해 그 자원이 있는 주소를 사용하는 방식입니다.
URL은 인터넷에서 웹페이지, 이미지, 비디오등 리소스의 위치를 가리키는 문자열 입니다.
예) 서울시/강남구/테혜란로/427
URN은 Uniform Resource Name의 약자로, 자원에 이름을 부여해서 구별하는 방식입니다.
이름 부여만으로는 찾을수가 없고 이름에 리소스가 매핑이되어있어야 찾을 수 있는데, URN은 거의 사용되지 않고 있습니다.
예) 위워크선릉2호점
아래이미지는 URL과 URN의 구조입니다.
URN은 거의 사용되지 않기 때문에 URL, URI를 혼용해서 사용하기도 합니다.
<URL을 분석해보자 >
- Scheme(스키마): 주로 프로토콜 정보
프로토콜은 어떤 방식으로 자원에 접근할지에대한 약속입니다...예) http, https, ftp
http는80, https(http에 강력한 보안이 적용된것으로, 현재는 거의 https를 사용) 443 포트 주로 사용해서 이 포트사용시 생략가능합니다. - userinfo : url에 사용자정보 포함해서 인증해야될때 사용하는데 거의 쓰지 않습니다.
- host : 도메인명이나 IP주소 직접입력
- port: 유명한 포트 생략가능. http 80, https 443
- path: 리소스의 경로. 계층적 구조로 되어있다.
home/file1.jpg /members /members/100/ites.ifom이렇게 계층적으로 설계해야 이해가 쉬워집니다.
/home/members/100 - query parameter: ?q=hello
쿼리파라미터, 쿼리스트링 으로 부른다. 다 문자형태로 넘어감(숫자로 적어도 문자로 변환되어 넘어간다)
key=value형태.
쿼리파라미터는 ?로 시작해야됨 & 로 추가 가능 - #fragment: html내부에서 어떤 위치로 이동하고싶을때 쓴다. 서버로 전송되지는 않는다.
b. URI, 웹브라우저 요청흐름
웹브라우저가 주소창에 주소를 쳐서 URL을 호출하면 이런일이 일어나게 됩니다.
1. https://www.google.com:443/search?q=hello&hl=ko 검색을 했다고 가정해보겠습니다.
2. 먼저 www.google.com으로 DNS 서버를 조회하고, 거기에서 IP주소를 알아냅니다.(200.200.200.2)
3. 그리고 포트정보도 찾아냅니다.(443)
4. 그런 후에 http요청메세지를 생성합니다.
5. 웹브라우저가 HTTP메세지를 생성하면 메세지를 소켓라이브러리를 통해 OS의 TCP/IP 계층에 전달합니다.
6. OS에 메세지를 전달하기 전에, IP와 PORT정보는 이미 찾은 상태이기 때문에 syn ,syn+ack, ack를 통해 3way handshake를 하고 구글서버와 연결합니다.
7. 그리고 나서 인터넷으로 보내기 위해 데이터를 OS로 전달합니다. 거기에서 TCP/IP패킷을 만들고 인터넷에 보내게 됩니다.
패킷 안에는 생성된 인터넷 메세지가 들어있습니다. 그러면 수많은 인터넷망의 노드들을 통해 목적지에 전달이 됩니다.
8. 요청패킷이 목적지인 구글서버에 도착하면 TCP/IP패킷을 벗겨서 버리고 HTTP메시지를 해석합니다.
9. q가 hello고 hl이 ko이니 hello를 검색하고 한국어결과를 찾습니다.
10. 그런 후에 구글웹서버에서 HTTP응답메세지를 만들고 응답을 보내게 됩니다.
TCP/IP 패킷 씌운 응답패킷을 클라이언트로 응답을 보냅니다.
11. 클라이언트에 도착해서 TCP/IP를 벗기고 HTTP 메세지를 열면 그 안에 HTML데이터 들어있고 그 내용으로 웹브라우저가 렌더링 쫙 하게됩니다.
3. HTTP 기본
HTTP는 HyperText Transfer Protocol의 약자로, 문서 간에 링크를 통해 연결할 수 있는 HTML(Hypertext Markup Language)을 전송하기 위한 프로토콜로 시작했지만, 지금은 html 뿐만 아니라 이미지, 음성, 영상, 파일, JSON, XML 등 거의 모든 것을 전송할 수 있게 되었습니다.
요즘은 클라이언트-서버 간의 통신 뿐만 아니라, 서버 간에도 데이터를 주고받을때도 HTTP를 사용합니다.
게임서버 거나 아주 특수한 경우 빼곤 http통신을 사용한다고 합니다.
그래서 지금은 HTTP가 거의 모든 것을 전송할 수 있도록 바뀌었다는 것입니다.
HTTP의 역사를 잠깐 보면, 여러 버전이 있지만 현재까지도 97년 등장한 http/1.1이 가장 많이 사용되고 있습니다.
http/1.1에 대부분의 기능이 들어있고 97 → 99 → 14년 개정되었기 때문에, 지금도 http의 기능에 대해 공부하려면 http/1.1을 공부하면 됩니다.
http/2, http/3는 성능 개선에 초점이 맞춰져 있습니다.
<HTTP 버전별 기반 프로토콜>
- TCP: HTTP1.1, HTTP/2
- UDP: HTTP/3 TCP기반 통신은 속도가 매우 빠른 메커니즘은 아닙니다.. 3 way handshake도 해야 하고, 보내야 하는 정보도 많아서 조금 느릴 수 있습니다. 이 때문에 애플리케이션 레벨에서 성능 최적화 되어 나온 HTTP/3에서는 UDP를 사용합니다.
현재 HTTP/1.1 주로 사용하고 있지만 HTTP/2, HTTP/3도 점점 증가하는 추세라고 합니다.
<HTTP 특징>
- 클라이언트 서버구조
- 무상태 프로토콜
- 비연결성
- HTTP메시지
- 단순함, 확장가능
a. 클라이언트, 서버 구조
HTTP에서는 서버와 클라이언트 개념이 분리되어 있습니다.
- 서버: 서비스를 제공하는 소프트웨어가 실행되는 컴퓨터
- 클라이언트: 서비스를 사용하는 컴퓨터
컴퓨터와 컴퓨터가 통신하는 구조입니다. 클라이언트가 요청하면 서버가 응답하는 방식으로 작동합니다.
b. 무상태 프로토콜을 지향한다
HTTP는 서버가 클라이언트의 상태를 보존하지 않는 stateless한 프로토콜을 지향합니다.
stateful과 stateless를 구분해 보면,
- stateful: 상태를 유지한다. 서버가 클라이언트의 이전 상태를 보존한다는 의미입니다.
- stateless: 상태를 유지하지 않는다. 이전 요청을 기억하고 있지 않다는 의미입니다.
상태유지는 중간에 응대해 주던 대상이 바뀌면 안 됩니다. 아니면 바뀔 때마다 정보를 다 넘겨줘야 합니다.
상태유지의 경우에는 항상 같은 서버가 유지되어야 하기 때문에 중계서버가 같은 서버로 연결시켜줘야 하거나,
중간에 그 서버에 오류가 발생하면 클라이언트는 처음부터 다시 요청해야 합니다.
상태유지에서는 요청할 때 이전상태를 기억하고 있을 것이라고 가정하고 요청하기 때문에, 중간에 서버가 바뀌면 에러가 날 것입니다.
예)
request: 장바구니 목록 줘
response: 누구의 장바구니 목록이지?? 이전에 상태를 기억하고 있는 서버가 아니라서 알 수 없음
무상태라면 중간에 응대해 주던 대상이 이 바뀌어도 됩니다. 그 요청만으로 서버에서 필요한 정보를 모드 받을 수 있기 때문입니다.
무상태의 경우에는 클라이언트가 필요한 정보를 다 담아서 보내기 때문에, 서버는 클라의 상태를 갖고 있을 필요가 없습니다.
예를 들어 갑자기 서버 1이 장애가 나면 중계서버가 서버 2로 던져버려도 중간에 문맥이 필요 없기 때문에 장애 없이 응답할 수 있게 됩니다.
서버가 이전 요청의 문맥을 기록하고 있지 않아도 되기 때문에, scale out(서버증설)에 유리하게 되는 것입니다.
무상태 프로토콜로 서버를 설계한다면 이벤트 때문에 서버에 요청이 몰렸을 때에도 서버에서 손쉽게 장비를 수백 대 증설할 수 있습니다.
하지만 현실에서는 모든 걸 무상태로 할 수 없을 수도 있고, 상태를 유지해야 하는 경우가 필요할 때가 있을 수 있습니다.
대표적으로 로그인이 있는데, 로그인한 상태가 유지되지 않는다면 쇼핑몰에서 옷을 구매하려고 로그인했는데도 페이지를 이동할 때마다 계속 다시 로그인을 해야 할 것입니다.
이때는 일반적으로 브라우저쿠키랑 서버 세션을 사용해서 상태를 유지합니다.
c. 비연결성
기본적으로 연결을 유지하는 연결지향형에서는 서버는 클라이언트가 요청하고 있지 않을 때도 연결 유지하느라 서버자원을 소모하고 있어야 합니다.
하지만 HTTP는 요청하고 서버가 응답하면 바로 연결 끊기 때문에 서버입장에서 자원을 절약할 수 있습니다.
클라를 수만대로 가정해 보면 엄청난 자원을 아낄 수 있게 된다는 것을 상상해 볼 수 있습니다.
1시간 동안 수천 명이 서비스를 사용하고 요청한다고 해도, 초로 나누면 서버가 1초에 처리하는 작업은 수십 개 이하로 매우 적기 때문에,
서버입장에서는 자원을 효율적으로 사용할 수 있게 됩니다.
비연결성의 단점은, 기본적으로 TCP/IP 연결 후 통신을 했더라고, 페이지 넘어가려면 다시 TCP의 3 way handshake를 통해 연결해야 하기 때문에 시간이 또 추가가 된다는 것을 들 수있습니다. 이런 지연은 사용자입장에서 단점이 될 수 있습니다.
예를들어 웹브라우저로 요청하면 CSS, JS, 이미지 등 많은 자원을 다운로드해서 페이지를 구성합니다. 하지만 이런 자원을 하나하나 받을 때마다 연결하고 받고끊고 다시 연결하는건 비효율적 이고 시간을 소요하는 과정이 될 것 입니다.
그래서 HTTP는 이런 단점을 보완하기 위해 기본적으로 지속연결(persistent connections)을 사용하고 있습니다.
HTTP초기에는 자원 하나 받을때마다 연결하고 종료하고를 반복하는 비효율적인 시스템이었습니다.
지속연결을 사용하면 연결 요청~응답 요청~응답 간의 시간을 몇십 초간 유지한 후 연결을 종료하거나, 필요한 리소스를 다 받게 되면 연결을 종료합니다.
d. HTTP 메세지
HTTP메세지에는 요청메세지와 응답메세지가 있습니다.
요청, 응답메세지는 좀 다르게생겼지만,구조의 틀은 같습니다.
아래 그림에서 볼 수 있듯이 HTTP의 메세지 구조의 공식 스펙은 다음과 같습니다.
statrline, header, empty line(CRLF(줄바꿈)), [message body]는 옵셔널 하다는 것 입니다.
주의할 점은 message body가 없더라도 header다음 줄바꿈은 필수로 포함되어 있어야 합니다.
바디에는 실제 전송할 데이터를 넣어서 보내는데, HTML 문서, 이미지, 영상, JSON등등 byte로 표현할수 있는 모든 데이터 를 전송할 수 있습니다.
응답메세지는 요청메세지와 조금 다르다고 했는데, start-line이 request-line or status-line 로 다르고. 다른 것은 동일합니다.
요청메세지 이미지에는 없지만 요청메세지에도 message-body를 가질 수 있습니다.
HTTP 메세지를 더 자세히 살펴볼까요?
<start-line 시작라인>
start-line 은 크게 request-line/ status-line 로 구분할 수 있는데,
요청메세지에서는 request-line을 응답 메세지에서는 status-line을 사용합니다.
<요청 메세지 start-line: request-line>
method SP request-target SP HTTP-version CRLF(엔터)
GET /search?q=hello&hl=ko HTTP/1.1
1) HTTP method: GET, POST,PUT,DELETE …
서버가 수행해야될 동작 지정
2) request-target(path 요청대상)
absolute-path?query
보통 절대경로로 지작하고 쿼리도 합쳐서 들어갑니다.
전체 http가 들어가는 경우도 있지만 거의 절대경로로 시작합니다.
3)http version
앞에서 현재는 http/1.1 버전이 대부분 사용되고 있고, http/2, http/3은 http/1.1을 개선한 버전이라고 설명했습니다.
<응답메세지 start-line: status-line>
HTTP/1.1 200 OK
Http-version SP status-code SP reason-phrase CRLF
1. http-version: 클라이언트-서버가 통신에 사용하고있는 HTTP 버전을 보냅니다
2. status-code: 클라이언트의 요청이 성공했는지 실패했는지를 보냅니다.
200번대 성공, 400번대 클라이언트 요청 오류 ,500번대 서버내부오류
reason-phrase: 사람이 이해할 수 있는 짧은 상태 코드 설명 글
<HTTP 헤더>
Host: www.google.com
header-field = field-name“:”OWS field-value OWS
(OWS: 띄어쓰기 허용한다는 뜻)
헤더에는 Http전송에 필요한 모든 정보가 들어있는데, 메세지바디가 어떤언어로 되어있는지, 메세지 바디의 크기 , 압축여부, 인증정보, 요청클라이언트의 웹브라우저 정보도 들어있습니다.
응답 헤더에는 서버애플리케이션이 뭔지도 들어있고, 캐시정보도 들어있습니다.
표준헤더필드는 아주 종류가 많고, 필요시 임의의 헤더도 추가할 수 있습니다.
- Host : www.google.com은 안됨 띄어쓰기 주의!
- field-name은 대소문자 구분 하지 않음
- field-value는 대소문자 구분함
<HTTP 바디>
바디에는 byte로 표현할 수 있는 정보들을 모두 담을 수 있습니다.
4. HTTP 메서드
URI설계에서 가장 중요한것은 리소스 식별입니다.
리소스가 뭘까요?
Resource란 자원, 재원, 재료를의미 합니다.
URI를 설계할때 '회원 등록', '회원 조회', '회원 수정' 자체는 리소스가 아닙니다.
search/user
update/user 이런식으로 자원이 아닌 것을 URI에 넣어서 설계하면 안된다는 것입니다.
예) ‘미네랄의 캐라’. 라고 하면 ‘미네랄’이 리소스지 ‘미네랄을 캐라’ 자체가 리소스가 아닙니다.
'회원등록', '회원조회'자체가 리소스가 아니고, '회원'이라는 개념 자체가 리소스입니다.
URI에서는 회원을 등록,수정,삭제하는 행위는 배제하고 회원이라는 리소스만 식별하는것을 지향해야 합니다.
그렇다면 이제 회원만 URI에 매핑하면 되는 것입니다.
앞에서 말했듯 URI 는 Uniform Resource Identifier로 리소스를 식별하는 통일된 방식 이라는 뜻인데요,
리소스를 쉽게 구별하는 방법은 명사를 리소스로, 동사를 메서드로 분리해 보는 것입니다.
URI는 리소스 식별, 계층구조로 설계한 모습은 아래와 같습니다.
- 회원 목록조회 /members
- 회원 조회 /members/{id}
- 회원 등록 /members/{id}
- 회원 수정 /members/{id}
- 회원 삭제 /members/{id}
그런데 행위를 빼고 리소스만 남기니 조회, 등록, 수정, 삭제 모두 다 같은 리소스에 대한 작업이기 때문에 URI가 똑같아져 버렸습니다.
우리가 리소스에서 빼낸 행위는 HTTP메서드를 사용해서 실행할 수 있습니다.
HTTP 메서드는 약 9~10개정도 됩니다.
HTTP메서드는 클라이언트가 서버에게 요청할때 기대하는 행동을 의미합니다.
a. GET
GET /search?q=hello&hl=ko HTTP/1.1
리소스 조회.
서버에 전달하고 싶은 데이터는 query (쿼리파라미터, 쿼리스트링)로 전달합니다.
보통 GET메서드 에서는 바디에 데이터를 넣지 않고, 전달할 데이터가 있으면 쿼리파라미터 , 쿼리스트링으로 전달합니다.
GET요청에도 메세지 바디를 전달할 수는 있지만 지원하지않는 곳이 많아 권장하지 않습니다.
b. POST
요청 데이터 처리, 주록 등록에 사용하지만 POST는 더 다양한 곳에서 사용되기도 합니다.
POST메서드는 스펙에 "대상 리소스가 리소스의 고유한 의미체계에 따라 요청에 포함된 표현을 처리하도록 요청합니다." 라고 되어 있습니다. 스펙의 정의마저 POST를 한가지 행동에 한정지어두지 않았습니다.
그래도 POST는 주로 사용되는 행동은 있습니다. POST는 신규리소스 등록하는 요청, 변경된 프로세스를 바꾸거나, 프로세스 처리하는 요청에 많이 사용합니다.
POST메서드를 사용한 요청에서는 메세지 바디를 통해 서버로 요청 데이터를 전달하는데,
서버는 메세지 바디를 통해 들어오는 '데이터를 처리하는 모든 약속된 기능'을 수행합니다.
POST /memebers HTTP/1.1
바디를 {”username”:”haha”} 라고 클라이언트가 보내면 서버가 그 데이터를 저장하기로 약속되어 있어야 합니다. 아니면 뭔가 내부적 프로세스에 쓸거라고 미리 약속을 해둬야합니다.
<신규 자원 생성에 사용합니다>
신규로 자원이 생성되면 보통 HTTP/1.1 201 Created 로 응답해주고,
Location으로 생성된 자원의 위치도 보내줍니다.
또 POST는 게시판에 글쓰기, 댓글 달기에도 사용 합니다.
서버가 아직 식별하지 않은 새 리소스 생성, 기존자원에 데이터 추가할때도 POST를 사용합니다.
이것이 POST에는 의미가 많다고 했던 이유입니다.
POST는 명확히 정의된 역할이 없기 때문에 어떻게 처리할지 리소스마다 스스로 정의해야합니다.
<서버에서 큰 프로세스를 처리할 필요가 있을때 사용합니다>
단순히 저장하고 변경하는게 아니라 서버에서 뭔가 프로세스를 처리해야하는경우에도 POST를 사용하는데요,
꼭 새로운 리소스가 생성되지 않더라도 서버에서 큰 변화가 일어난다면 POST를 씁니다.
주문 → 결제완료 → 배달시작 → 배달완료 처럼 단순히 값 변경을 넘어 프로세스의 상태가 변경되는경우.
라이더가 호출되고.. 하는 뒤에선 큰 변화가 일어나는 작업에는 POST를 사용합니다.
<컨트롤 URI를 사용할때 POST메서드를 사용하기도 합니다>
앞에서 리소스와 메서드를 분리해야하고, 명사형을 리소스로, 동사를 메서드로 분리해보라고 말했었습니다.
하지만 실무에서는 URI에 리소스만 사용해서는 부족할 때가 있습니다. 이럴때는 동사형을URI에 사용하는 컨트롤 URI를 쓰게되고, 이때 POST 메서드를 많이 사용합니다.
POST /orders/{orderId}/start-delivery (동사지만 URI에 사용한다, 컨트롤 URI라고 부른다.)
여기에서 start-delivery가 컨트롤 URI입니다.
<메세지 바디가 필요한 조회일때 POST를 사용합니다>
쿼리 파라미터 말고 json으로 조회하는 데이터를 넘겨야 하는데 GET메서드는 보통 메세지 바디를 지원하지 않는 경우가 많습니다.
그럴때에는 조회에 POST를 쓰고, 메세지 바디에 조회용 데이터를 넘기게 됩니다.
POST는 사실 모든걸 할수있지만 조회에는 GET을 쓰도록 설계하는것이 좋습니다.
그 이유는 GET이 오면 캐싱을 하게끔 서버끼리는 약속이 되어 있는데, POST로 조회 요청이 오면 캐싱이 어렵기 때문입니다.
c. PUT
리소스가 있다면 리소스를 대체하고 , 해당리소스 없으면 생성합니다.
파일을 폴더에 넣는거랑 비슷하다고 생각하면 됩니다.
리소스가 이미 있다면 덮어버리기때문에 기존에 있던 값은 사라진다는점을 주의해야합니다.
d. PATCH
리소스 부분 변경합니다.
리소스를 부분적으로 변경하고 특정필드를 몇개 바꿀때 사용합니다.
e. DELETE
리소스 삭제에 사용합니다.
f. 그외
- HEAD: GET 과 동일하지만 메세지 부분 빼고, 상태줄, 헤더만 반환
- OPTIONS: 대상 리소스에 대한 통신가능 옵션을 설명(주로 CORS에서 사용)
거의못보는 두가지 - CONNECT: 대상 자원으로 식별되는 서버에 대한 터널을 설정
- TRACE: 대상 리소스에 대한 경로를 따라 메세지 루프백 테스트를 수행
5. HTTP 상태코드
상태코드는 클라이언트가 보낸 요청의 처리 상태를 응답에서 알려주는 기능입니다.
100번~500번대의 코드로 요청의 처리상태를 알 수 있습니다.
- 1XX(Information): 요청이 수신되어 처리중
- 2XX(Successful): 요청 정상처리
- 3XX(Redirection) : 요청 완료하려면 추가행동 필요
- 4XX (Client Error): 클라이언트 오류. 잘못된 문법등으로 서버가 요청수행할 수 없음
- 5XX (Server Error): 서버오류. 서버가 정상 요청을 처리하지못함
* 만약 클라이언트가 인식할 수 없는 상태코드를 서버가 반환하게 되면 클라이언트는 상위 상태코드로 해석해서 처리합니다.
예를들어 299라는 상태코드를 반환하면 그 상위 상태코드인 200번대 코드로 인식하여 요청 성공으로 간주한다는 것 입니다.
299 -> 2XX(Succsssful)
452 -> 4XX( Client Error)
a. 1XX
요청이수신되어 처리중이다. 거의 사용하지 않습니다.
b. 2XX (성공)
HTTP 응답메세지의 형태를 기억하고 계신가요?
응답메세지 start-line으로 상태코드와 상태 메세지를 보내줍니다
HTTP/1.1 200 OK
200 OK
201 Created 클라이언트 요청으로 서버쪽에서 리소스 생성함(주로 POST 응답으로 온다)
응답헤더에 생성된 리소스의 URI를 넣어준다 Location: /members/100
202 Accepted 요청이 접수되었으나, 아직 처리가 완료되지 않음
204 No Content
클라이언트가 요청하면 보통 서버가 응답 바디를 보내주는데, 서버가 요청을 성공했지만 응답으로 본문에 보낼 데이터가 없는 경우 사용합니다.
예) 웹 문서 편집기에서 저장버튼 누른경우. 본문을 응답으로 다시 받을필요는 없는 경우에 사용합니다.
이 외에도 성공 응답코드 종류가 많지만 거의 200만 사용하는 경우도 많습니다. 모든 코드를 사용하겠다고 하면 개발범위가 너무 넓어지기 때문에, 개발시 내부 범위는 잡고 쓰는것이 좋습니다.
c. 3XX (리다이렉션)
요청을 완료하려면 추가작업이 필요한경우에 300번대의 응답이 옵니다.
웹브라우저는 3XX응답결과에 Location헤더가 있으면, Location 위치로 웹브라우저가 자동으로 이동시켜 줍니다.(리다이렉트)
예) 이벤트페이지의 주소가 변경된 경우. 기존에 공유된 링크로 유저가 들어온 경우 새로 갱신된 페이지로 이동시켜줘야 한다.
301 리다이렉트 응답을 보내고 Location으로 새로운 주소를 보내주면 웹브라우저가 자동으로 새 주소로 이동시킴
<리다이렉션의 종류 3가지>
- 301, 308 영구 리다이렉션: 특정 리소스 URI가 영구적으로 이동됨
- 일시 리다이렉션: 일시적 변경
예) 주문완료 후 주문내역 화면으로 이동시키는 경우
- 특수 리다이렉션: 결과 대신 캐시를 사용
캐시가 만료된경우를 검사하려고 캐시생성일자를 클라가 서버에 넘겨줬는데 아직 만료되지않아 캐시에 있는 데이터를 사용하라고 응답이 오는 경우
d. 4XX (클라이언트 오류)
오류의 원인이 클라이언트에 있음.
클라이언트에서 이미 잘못 요청하고 있기 때문에, 똑같은 재시도가 실패합니다.
- 400 Bad Request: 요청구문, 메세지 등등 오류
- 401 Unauthorized: 인증오류
- 403 Forbidden: 접근권한이 불충분한 경우
- 404 Not Found: 요청리소스를 찾을 수 없음
e. 5XX (서버 오류)
서버문제로 오류 발생한 경우로, 클라이언트가 같은 요청을 해도 실패했던 것이 성공할 수 있습니다.
- 500 Internal Server Error 서버내부문제로 오류 발생
- 503 Service Unavailable 서비스 이용 불가
* 서버에 문제가 났을때만 500대 에러를 발생시켜야 합니다.
예시1) 비즈니스 로직상 고객잔고가 부족할때 인출 시도 했을때는 500에러를 내면 안됩니다.
예시2) 20세 이상에게만 제공하는 서비스인데 15세가 요청했을경우엔 500에러를 내면 안됩니다. 이것은 정상 프로세스이고, 비즈니스로직상 예외케이스일 뿐이기 때문입니다.
6. HTTP 헤더
1) 일반 헤더
header 형식은 field-name":"OWS field-value OWS(띄어쓰기 허용)
필드네임은 대소문자 구분이 없습니다. 필드벨류는 대소문자를 구분합니다.
예) Content-Type: text/html;charset=UTF-8
- HTTP 전송에 필요한 모든 부가정보를 헤더에 담아 전송합니다.
예) 메세지 바디의 내용, 메세지바디 크기, 압축방식, 인증,요청 클라이언트, 서버 정보, 캐시 관리정보 등
- 표준헤더 종류는 아주 많습니다
- 필요시에는 임의의 헤더도 추가할 수 있습니다.
a. 표현 헤더
과거 RFC2616에서는 헤더를 4가지로 분류했었습니다.
- General header: 메세지 전체에 적용되는 정보
- Request header: 요청정보, 예) User-Agent:Mozilla...
- Response header: 응답 정보 예) Server: Apache
- Entity header: 엔티티 바디 정보 예) Content-Type: text/html, Content-length: 3410
이 중에서 Entity header는 메세지 본문에 들어가는 내용을 해석할 수 있는 정보를 제공해주고,
데이터 유형, 데이터 길이, 압축정보 같은 정보들이 엔티티 헤더에 들어가 있었다.
그런데 HTTP표준에 2014년 RFC 7030~7035가 등장하게되어 많이 개정되고, RFC2616은 폐기되었다.
RFC 723X에서는
- 엔티티(Entity) -> 표현(Representation)으로 용어가 변경되었습니다.
- Representation = Representation Metadata + Representation Data
표현은 표현에대한 메타데이터와 표현데이터를 합친 것을 말한는데,
최신스펙에서는 메세지 본문을 통해 표현데이터를 전달합니다.
메세지 본문을 페이로드라고 합니다.
표현은 요청이나 응답에서 전달할 실제 데이터를 말합니다.
표현헤더는 표현데이터를 해석할 수 있는 정보를 제공합니다. 요청과 응답에서 모두 사용할 수 있습니다.
회원이라는 리소스가 있을때, 이 리소스는 클라이언트와 서버가 주고받을때 다양한 포멧으로 주고받을 수 있게 됩니다.
회원데이터는 HTML로 주고받기도, JSON으로 주고받기도 할 수 있는데 이렇게 다양한 방법으로 형식을 "표현"해서 전송하게 됩니다.
표현헤더는 표현데이터에 대한 정보를 담고있는 헤더로 다음과 같습니다.
- Content-type : 표현 데이터의 형식
리소스를 표현 하려면 어떤 형식(JSON, XML ...)으로 전송되는지 알아야 하는데, 표현의 데이터 타입을 헤더로 알려줍니다.
예) text/html; charset=utf-8
application/json
image/png - Content-Encoding: 표현 데이터의 압축 방식
데이터를 전달하는 곳에서 압축 후 인코딩 헤더를 추가해주고,
데이터를 읽는 쪽에서 인코딩 헤더의 정보로 압축을 해제할 수 있습니다.
예) gzip, deflate, identity - Content-Language: 표현 데이터의 자연연어를 표현
이 표현데이터가 한국어인지 영어인지를 알려줍니다.
예) ko, en, en-US
만약 Content-Languate: ko 가 헤더에 들어있다면, 본문내용에 한국어가 들어있다는것을 알수 있게 됩니다. - Content-Length: 표현 데이터의 길이
표현데이터의 길이를 저장하고 있는 정보입니다.
b. 콘텐츠 협상 헤더
Content Negotiation
클라이언트가 선호하는 표현(Representation)으로 달라고 서버에 요청하는 것입니다.
이 요청을 받은 서버는 클라이언트가 원하는 표현을 우선순위를 나열해서 보내면, 서버는 최대한 우선순위가 높은 데이터 표현으로 만들어 주게 된다.(지원하는 형식이라면)
* 협상헤더는 요청시에만 사용합니다
- Accept: 클라이언트가 선호하는 미디어 타입 전달
- Accept-Charset: 클라이언트가 선호하는 문자 인코딩
- Accept-Encoding: 클라이언트가 선호하는 압축 인코딩
- Accept-Language: 클라이언트가 선호하는 자연언어(ko, en ..)
c. 전송방식
전송방식에는 크게 4가지가 있는데, 전송방식에 대한 정보도 헤더로 전달합니다.
- 단순전송: 요청에 대한 응답으로 메세지바디의 길이를 보내줍니다. 바디의 전체길이를 알수있을때 단순전송을 사용할 수 있습니다. Content-length: 3220
- 압축전송: 어떤 압축방식을 사용했는지 Content-Encoding: gzip
- 분할전송: Transfer-Encoding: chunked
나눠서 보내는 패킷의 각 크기가 적혀져있다. 전체 바디길이를 보내면 안됨(Content-Length는 보내면 안된다)
- 범위전송: 용량이커서 중간에 끊긴경우, 못받은 리소스의 범위를 요청하면 응답으로 그 부분만 받을 수 있습니다
요청시 Range: bytes 1001-2000
응답시 Content-Range: bytes 1001-2000 / 2000
<인증과 쿠키>
쿠키는 클라이언트 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일입니다.
사용자 인증이 유효한 시간을 명시할 수 있고, 유효시간이 정해져있다면 브라우저가 종료돼도 인증이 유지됩니다.
쿠키는 클라이언트 상태 정보를 로컬에 저장했다 참조합니다.
브라우저를 사용해서 서버에 요청을 보낼때, 따로 요청하지 않아도 브라우저가 request header에 쿠키를 넣어서 전송합니다.
<쿠키의 동작 방식>
- 클라이언트가 페이지를 요청
- 서버에서 쿠키를 생성
- HTTP 헤더에 쿠키를 포함 시켜 응답
- 브라우저가 종료되어도, 쿠키 만료 기간이 남아있으면 클라이언트에서 보관하고 있음
- 같은 요청을 할 경우 HTTP 헤더에 쿠키를 함께 보냄
- 서버에서 쿠키를 읽어 이전 상태 정보를 변경 할 필요가 있을 때, 쿠키를 업데이트 하고 변경된 쿠키를 HTTP 헤더에 포함시켜 응답
쿠키는 로그인을 했을때 set-cookie형태로 서버에서 반환받은 쿠키를 토대로 로그인이 필요한 요청을 할때마다(권한필요한 요청) 받은 쿠키를 같이 보내서 요청하는 동작구조 입니다.
이렇게 쿠키를 사용하는 이유는 특정 정보를 저장해야 했기 때문이다.
예로 들면 최초로 ID, PW를 가지고 로그인 한 후에는 별다른 ID, PW없이 로그인된 상태에서 요청을 날릴 수 있게 되었다. http는 무상태 프로토콜이기 때문에 쿠키가 없다면 요청을 보낼때 마다 ID, PW를 입력받아야 했을 것입니다.
하지만 현재는 다음과같은 단점들때문에 쿠키만을 온전히 인증에 사용하지 않고 있습니다.
- 쿠키는 ID,PW를 저장해두고 요청시 전송하기때문에 중간에노출되었을때 ID, PW가 모두 노출된다
- 조작당해서 들어올 가능성이 있다
- 브라우저마다 쿠키에 대한 지원형태가 달라 다른 브라우저간의 공유가 불가능히다.
- 쿠키의 사이즈가 제한되어있어(4KB, 4000자) 원하는만큼 충분한데이터를 담을수 없다
- 서버는 매번 ID,PW를 받아서 인증해야하는 불편함이 있고, 조작된 데이터가 넘어와도 방지할 수 없다.
<Cookie & Session을 사용하는 경우>
쿠키만 사용하는 방식에서 개선된 방식으로 쿠키와 세션을 사용하는 방식이 등장했습니다.
쿠키라는 정보저장체 자체를 주고받는다는 것에는 변함이 없지만, ID, PW를 직접 주고받는게 아닌 다른 방식을 사용해서 보안을 강화한 방식입니다.
서버에서 발급한 Session ID를 서버의 세션 저장소에 저장하고, 세션ID를 특정한 형태(쿠키 or json)로 클라이언트에 반환하여 클라이언트에 저장하도록 합니다.
클라이언트는 사용자 인증이 필요한 정보를 요청할때마다 이 세션ID를 쿠키에 담아 서버에 전달합니다.
인증이 필요한API라면 서버는 클라이언트에서 보낸 세션ID가 세션저장소에 있는지 확인하고,세션 저장소에 있다면 인증 완료후 API처리하고, 없으면 401에러를 반환합니다.
완전 쿠키만 전송할때와는 달리 세션저장소에 식별할 수 있는 값을 넣어두고 그 값이 일치되는지 확인할 수 있어서 보안 문제가 개선되었습니다.
만약 보안문제 발생하면(세션ID 탈취문제 발생) 세션저장소를 전부 지워버리면 해결할 수 있게 됩니다.
하지만 세션저장소가 어떤 이유로 장애가 나게되면 인증 전체에 문제가 생기게 되어 사용자에게 불쾌한 경험을 줄 수 있는 위험이 있는 방식이기도 합니다. 또, 서버에서 세션저장소라는 별도의 저장소를 관리해야한다는 단점이 있습니다.
그런 단점을 보완한것이 토큰을 이용한 인증방식입니다.
JWT는 인증에 필요한 정보들을 암호화해서 사용하는 토큰입니다.
JWT는 JSON형식의 토큰에 대한 표준 규격으로, 주로 사용자 인증 정보를 서버와 클라이언트가 안전하게 주고받기 위해 사용합니다.
중요한것은 JWT는 서명된 토큰이라는 것입니다.
클리이언트가 보낸 토큰을 서버는 서명은 서명 할 때 사용한 키를 사용하여 JSON이 손상되지 않았는지 확인해서 인증할 수 있습니다.
JWT 의 주요한 이점은 사용자 인증에 필요한 모든 정보는 토큰 자체에 포함하기 때문에 별도의 인증 저장소가 필요없다는 것입니다.
2) 캐시와 조건부 요청
헤더를 사용해 웹캐시를 설정할 수 있습니다.캐시를 사용하지 않으면 같은 데이터라도 계속 다시 받아와야하는 일이 발생합니다. 하지만 네트워크를 왔다갔다하는것은 비용이 큰 작업입니다. 따라서 재사용할 수 있는 데이터가 있다면 어딘가에 저장해두고, 필요할때 거기에서 가져다 쓰는 방법이 있는데, 이것이 캐시를 사용하는 이유입니다.
헤더를 통해 캐시를 컨트롤 할 수 있습니다.
a. 캐시지시어(directives)
- Cache-Control: max-age=3600 캐시가 유효한 을 초단위로 제공합니다.
- Cache-Control: no-cache 이름과는달리 캐시관리자에게 캐시는 허용하지만, 항상 오리진서버에 유효성을 체크하고 사용해야합니다(프록시서버가 아닌 origin서버!)
- Cache-Control: no-store 민감한 정보가있으므로 저장하면 안된다는 헤더입니다(메모리에서 사용하고 최대한 빨리 삭제)
- Cache-Contol: must-revalidate 캐시관리자에게 내부유효성 체크를 허용하지 않고, 항상 서버에 유효성 체크하도록 합니다
b. 검증헤더와 조건부 요청
캐시를 사용해도 되는경우 서버에서 캐시유효시간을 제공해주는데요, 서버의 데이터와 캐싱된 데이터가 일치해서 유효 시간은 지났더라도 캐시데이터를 사용해도 되는 경우가 있습니다. 이때 검증에 사용하는것이 검증헤더와 조건부 요청입니다.
- Last-Modified, if-Modified-Since :
캐시의수정시간을 가지고 비교해서, 캐시 유효시간이 지났더라도 갖고있는캐시와 서버데이터가 일치한다면, 캐시해둔 데이터를 사용합니다.
- ETAG, If-not-match :
데이터 버전으로 체크해서 서버데이터와 일치하면 캐시해둔 데이터를 사용합니다.
c. 프록시캐시
해외서비스의경우 프록시 서버에 캐싱을 해두면, 한번 받은 데이터는 다른사람이 받아볼때 좀 빠르게받을수있습니다.
ex) 유튜브 유명한 영상은 로딩이 빠른이유
d. 확실한 캐시 무효화 응답
캐시를 하지않도록 헤더르 설정해도, GET요청시 브라우저가 임의로 캐싱하는경우도있음 .
캐시가 항상 오리진 서버에 캐시된 데이터의 유효성을 확인하도록 캐시를 완전 무효화시키려면 아래 헤더들을 모두 사용해야 합니다.
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
지금까지 강의를 정리하고 중간중간 궁금한 내용을 추가하는 방식으로 HTTP에 대해 알아 보았습니다. 캐시같은 내용은 웹브라우저에서만 적용되는 내용으로 앱개발에는 적용하기 어렵겠지만, 그동안 발전해온 HTTP에서 사용되는 방식들을 앱개발에도 적용해 볼 수 있을 것입니다.
미뤄오던 HTTP에 대해 공부하면서 시야가 넓어지는 경험을 했습니다. 앞으로의 세미나를 통해서도 CS지식을 넓혀갈 수 있다면 좋겠습니다.
공부를 정리하는 방식이라 정리한 강의뿐 아니리 다른 자료들의 도움을 정말 많이 받았습니다.
오류가 있다면 알려주시고 컨텐츠에 문제가 있다면 알려주시면 수정하도록 하겠습니다.
읽어주셔서 감사합니다
출처
https://www.inflearn.com/course/http-웹-네트워크
https://interconnection.tistory.com/74
https://meetup.nhncloud.com/posts/92
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers
http://www.opennaru.com/opennaru-blog/jwt-json-web-token/
https://velog.io/@kimdukbae/URI-URL-URN
'Flutter & Dart Seminar' 카테고리의 다른 글
[세미나] 각 언어별 가비지 컬렉션의 동작 방식 (0) | 2023.04.20 |
---|