과거 - HTML 문서를 통신하는 규약
현재 - HTML을 포함한 그 외 모든 데이터를 전송할 때 사용됨 ( Imgae,음성,영상,파일,Json,XML(api) ) 거의 모든 형태의 데이터를 전송할 수 있습니다.
TCP기반 프로토콜 : HTTP/1.1, HTTP/2
UDP기반 프로토콜 : HTTP/3
현재 유명 포털사이트들은 HTTP 1.1, 2, 3 를 모두 혼용해서 사용합니다.

복잡한 비즈니스 로직, 데이터 처리는 모두 서버쪽에서 처리하고 클라이언트는 오직 렌더링에만 신경쓰게 만들면 렌더링과 비즈니스 로직의 처리를 독립적으로 하기 때문에 효율도 좋아지고, 고도화도 독립적으로 진행하면 되서 편하다.
무상태 프로토콜 지향 (Stateless)
상태유지 프로토콜 지양 ( Stateful )
![]() | ![]() | ![]() | ![]() |
|---|---|---|---|
| 1. 서버가 클라이언트의 상태 "노트북"을 유지 2. 서버가 클라이언트의 상태 "2대"를 유지 3. "노트북" "2개" 상태를 가지고 결제 완료 | 위 예제는 클라이언트가 요청했을 때 모종의 이유로 서버가 변경되는 상황입니다. | 상태통신(Stateful)은 클라이언트의 상태를 서버가 유지,보존 하고있기에 클라이언트와 서버가 1:1로 대응 및 유지 되어야만합니다. | 클라이언트는 서버가 복구될때까지 기다리고 처음부터 다시 시작해야한다. |
![]() | ![]() | ![]() | ![]() |
|---|---|---|---|
| 무상태통신(Stateless)은 서버가 클라라이언트의 상태를 유지하지 않는다 하였습니다. 무상태 통신은 클라이언트가 서버에게 요청할 때 필요한 상태정보를 클라이언트 측에서 제공합니다. | 위 예제는 클라이언트가 요청했을 때 모종의 이유로 서버가 변경되는 상황입니다. | 무상태통신(Stateless)는 클라이언트의 상태를 클라이언트가 요청시 제공하기 때문에 서버가 변경되어도 에러가 생기지 않으며 서버의 확장이 매우 용이하다. | 서버 확장이 매우 용이하다. |
상태유지 : 중간에 다른 서버로 바뀌면 안된다. ( 변경시 바뀔 서버에게 정보 전달 해야함 )
무상태 : 중간에 다른 서버로 바뀌어도 된다. ( 클라이언트가 서버에게 필요한 정보를 모두 제공하기 때문에 )

웹 애플리케이션 설계시 최대한 무상태설계를하며 필요한경우에만 최소한으로 상태설계를한다.
HTTP는 무상태입니다.
다만, 무상태라는 특징을 가지는 HTTP에서 상태 유지를 위해 쿠키, 세션, 토큰과 같은 방법을 사용합니다.
로그인은 상태유지 일까요 무상태일까요
로그인을 "유지"하려면 로그인 "상태"를 서버에서 관리해야 합니다.
따라서, 로그인은 stateless가 될 수 없습니다.
다만, 토큰을 이용하는 환경에서는 stateless로 로그인을 구현할 수 있습니다.
HTTP가 무상태 특성을 갖는 이유
HTTP의 구조인 클라이언트 서버 구조가 하나의 요청과 응답안에서만 데이터를 유지하는 Request, Response 구조이기 때문입니다.
동일한 사이트(서비스)이지만 많은 사용자에게 서비스를 쾌적하게 제공하기 위해 동일한 기능을 수행하는 서버를 여러 대 사용할 수 있습니다. 각 서버는 서로 다른 IP를 가집니다.
사용자는 중계서버 IP만 알고 있으면 됩니다. 중계서버가 뒷단에 있는 서버1, 2, 3에게 요청을 위임하고 처리되는 응답을 받아서 사용자에게 전달할 것이기 때문입니다.
학습을 위한 추천 키워드
로드밸런싱, 프록시, 부하분산
HTTP의 연결 모델
![]() | ![]() | ![]() |
|---|---|---|
| 각 클라이언트가 서버와 연결을 유지하고 있으면 서버의 자원이 낭비되기 때문에 비효율적입니다. | HTTP 통신은 각 클라이언트와 요청 응답 과정이 끝나면 연결을 종료합니다. |
![]() | ![]() | ![]() |
|---|---|---|
| 페이지를 전환하게 되면 그에 따른 HTML,CSS,JS 등 렌더링에 필요한 데이터들을 전환할 때마다 요청( 통신 )해야한다. | 과거에는 렌더링에 필요한 데이터를 발견할때마다 계속 연결을 했어야 했습니다. | 현재는 렌더링에 필요한 데이터를 한번에 다 받고 연결을 종료합니다. |
![]() |
* start-line : request-line / status-line 시작 라인은 아래와 같이 나누어져있다. 요청/응답 시 표시되는 내용이 다르다. * request-line : HTTP 요청메시지의 규격 * status-line : HTTP 응답메시지의 상태 *header-field : host / content-type, content-length *host : HTTP 요청메시지의 규격 *content-type, content-length : HTTP 응답메시지의 규격 message body : 실제 전송할 데이터, HTML,이미지,영상,JSON등 byte로 표현할 수 있는 모든 데이터 전송 가능 |
![]() |
![]() |
| * start-line : method SP(공백) request-target SP HTTP-version CRLF(엔터) * 시작라인 : 메소드 + /경로 + 쿼리스트링 + HTTP버전 (일반적으로 경로는 절대경로 사용 /로시작) *header-field : host ( 요청할 호스트의 도메인 ) |
* start-line : HTTP-version SP + status-code SP + reason-pharse CRLF * 시작라인 : HTTP버전 + 상태코드 + 이유문구 ( 성공인지 실패인지 ) 상태코드 종류 = 200: 성공 / 400: 클라이언트 요청오류 / 500: 서버내부 오류 *header-field : HTTP 전송에 필요한 모든 부가정보 ex) 메시지바디의 내용, 메시지바디의 크기,압축,요청 클라이언트 정보 등 content-type : 파일 종류;인코딩방식 content-length : 응답해 줄 내용의 길이 |
요구사항 - 회원 정보 관리 API를 만들어라.
1.URI 설계
![]() | ![]() | ![]() |
|---|---|---|
| 이것은 좋은 URI 설계일까? URI는 리소스를 기준으로 설계해야한다. 명사와 동사를 구분하는게 바람직 합니다.. | 회원 관련 동작에서는 "회원" 이라는 명사가 리소스리이기 때문에 "회원" 리소스를 URI에 매핑 | 위와 같이 설계하는게 바람직하지만, 그렇다면 행위에 대해서는 어떻게 분리해서 적용할 수 있을까?, URI 설계도 개발에 있어서 변수와 함수를 생각하면 이해가 수월 할 것 같습니다. 위와 같이 설계하면 동사(행위)에 대해 구분하기가 어렵습니다. 이것을 해결해 주는것이 HTTP 메서드 입니다. |
GET : 리소스 조회
POST : 요청 데이터 처리, 주로 등록에 사용 ( 서버에 데이터를 보내는 용도 )
PUT : 리소스를 대체, 해당 리소스가 없으면 생성 ( 서버에 데이터를 보내는 용도 서버에 데이터가 없으면 새로 생성하고 있으면 덮어씌움 )
PATCH : 리소스 부분 변경
DELETE : 리소스 삭제
최근에는 리소스라는 표현이 레프레젠테이션이라는 용어로 바뀌었다고 합니다.
리소스 조회, 서버에 전달하고 싶은 데이터는 query string을 통해서 전달합니다.
메시지 바디를 통해 데이터를 전달할 수 있지만, 지원하지 않는 서버들이 많아서 사용을 권장하지 않습니다.
![]() | ![]() | ![]() |
|---|
서버로 요청을 보낼 때 메시지 바디를 통해서 데이터를 전달하고 서버에서 요청데이터를 처리하는 방식
주로 전달된 데이터로 신규 리소스 등록, 프로스 처리에 사용합니다.
필자는 전에 그누보드를 이용한 개발회사에서 근무한적이 있었습니다. 글을 작성하다보니 서버에서 DB 데이터를 처리했던게 기억이 납니다 ㅎㅎ..
요청 데이터 처리
메시지 바디를 통해 서버로 데이터 전달
서버는 요청 데이터를 처리
주로 전달된 데이터로 신규 리소스 등록, 프로세스 처리에 사용
![]() | ![]() | ![]() |
|---|---|---|
![]() | 주문 -> 결제완료 -> 배달시작 -> 배달완료 / 결제완료, 배달시작 같은 큼지막한 프로세스의 변화는 POST로 작업합니다. 그에따른 URI 설계도 달라질 수 있습니다.. ( 동사( 컨트롤URI )가 들어갈 수 있다는 말 ) GET 메서드는 메시지 바디를 허용하지 않는 서버가 많습니다. 이럴 때도 POST를사용합니다. GET 메서드는 캐싱을 해주기 때문에 "조회"에 이용할 때 유리합니다.( POST는 모든걸 할 수 있지만 각 메서드마다 장점이 있기에 사용에 유의합시다. ) |

리소스를 대체
클라이언트가 리소스 위치를 알고있어야한다. URI 지정
![]() | ![]() |
|---|---|
![]() | 기존에있던 데이터를 완전히 제거 후 새로작성 됩니다. 주의하세요. |
![]() | ![]() |
|---|
![]() | ![]() |
|---|

안전 ( safe )
호출해도 리소스를 변경하지 않는다.
Q: 무한대로 호출해서 에러가 생겨도 안전하지 않은가?
A: 안전은 리소스의 변경 가능성이 있는지만 고려합니다.
하나의 클라이언트가 같은 요청을 반복한다는 가정하에 생각해야 합니다.
호출 한 결과가 횟수에 상관없이 같을때 멱등성을 가진다고 합니다.

멱등 메서드
멱등한가 안한가는 외부의 요인을 고려하지 않는다. ( 같은 클라이언트가 같은 요청을 했을 때만을 고려합니다. )
응답 결과 리소스를 캐시해서 사용할 수 있는가? ( 브라우저 내부에 저장할 수 있는가? )
GET,HEAD, POST, PATCH
실제로는 GET, HEAD 정도만 캐시로 사용합니다.
POST, PATCH 는 본문 내용까지 캐시 키로 고려해야 하는데, 구현이 어렵고 실제 잘 사용하지 않습니다.
쿼리스트링을 통한 데이터 전송 ( GET 메서드 )
메시지 바디를 통한 데이터 전송
정적 데이터 조회
동적 데이터 조회
HTML Form을 통한 데이터 전송
HTTP API를 통한 데이터 전송
![]() | ![]() |
|---|---|
| 이미지, 정적 텍스트 문서 조회는 GET 메서드 정적 데이터는 일반적으로 쿼리 파라미터 없이 리소스 경로로 단순하게 조회 | 검색, 게시판 목록에서 검색어 필터 할 때 조회 조건을 줄여주는필터 등 GET메서드는 쿼리스트링을 사용해 서버에 데이더 전달 |
![]() | ![]() |
|---|---|
| HTML Form 태그 내부에 여러가지 데이터를 입력받고 Submit 버튼을 클릭하면 브라우저가 HTTP 요청메시지를 생성합니다. | GET 메서드로 변경해서 보낼 수 있으나 URL에 노출되기 때문에 단순 조회시에만 사용해야 합니다. |
![]() | ![]() |
|---|


![]() | ![]() | ![]() | ![]() |
|---|
리다이렉션의 이해
웹 브라우저는 3xx 번대 응답 결과에 Location 헤더가 있으면, Location 위치로 자동 이동( 리다이렉트 )
![]() | 상황 : 구형 이벤트 페이지에서 신형 이벤트 페이지가 개발되었고, 이전 사용자들은 구형 이벤트 페이지를 북마크 하거나, 과거 주소로 접속하게 됩니다. 위와 같은 상황에 301 응답결과와 함께 Location 헤더에 신형이벤트 페이지 URL를 주면 브라우저는 자동으로 신형 페이지로 리다이렉션 합니다. 마치 개인 전화번호가 변경되었을때 과거의 번호로 연락하면 변경된 전화번호로 자동으로 넘어가는것과 같은 맥락입니다. | ![]() |
|---|
영구 리다이렉션 응답코드 301과 308
일반적으로 이벤트 페이지가 변경되어서 리다이렉션이 필요하다면 신형 이벤트 페이지에서 필요한 데이터가 변경되어서 자주 사용되진 않습니다.
또한, 위의 의유로 사용해도 301을 많이 사용하는 편입니다.
![]() | 영구 리다이렉션 응답코드 301은 리다이렉션 과정중 요청이 일어날 때 HTTP 메서드가 POST 메서드로 되어있다면 GET 메서드로 자동 변경되고, 메시지 바디의 내용을 모두 제거해버립니다. |
|---|---|
![]() | 영구 리다이렉션 응답코드 308은 리다이렉션 과정을 마쳐도 메서드가 자동 변환되지 않고 메시지 바디의 내용도 유지됩니다. |
일시적 리다이렉션 응답코드 302, 303, 307
실무에서 가장 많이 사용합니다.
![]() | 302,303,307 모두 기능은 같으나 디테일이 다릅니다. 302 Found 는 요청메서드가 GET으로 변할수도있고 안변할 수도있습니다. 303 See Other 는 요청메서드가 GET으로 100% 변경됩니다. 307 Temporary 는 요청메서드, 메시지바디 모두 유지됩니다. 실무에서 302를 가장 많이 사용하고, 대부분의 프레임워크들의 디폴드가 302입니다. |
|---|
일시적인 리다이렉션의 문제점
POST 요청으로 사용자가 물건을 주문후에 웹 브러우저를 새로고침한다면 ?
브라우저는 새로고침 하게되면 마지막 HTTP 요청을 다시하게 됩니다.
위와 같은 상황에서는 중복 주문이 될 수 있습니다. ( 웹브라우저가 마지막 요청을 새로고침 하기때문에 포스트 요청을 다시 한다. )
PRG : Post/Redirect/Get ( post요청 -> 302응답 -> redirect -> Get )
![]() | 좌측 이미지에 일시적 리다이렉트의 문제점이 드러납니다.주문완료 페이지에서 새로고침 했을 뿐인데 DB에 주문데이터가 중복으로 저장되는게 확인됩니다. 이러한 문제점을 해결하기위해 PRG(Post/Redirect/Get) 방법을 사용합니다. |
|---|
위와 같은 문제는 클라이언트측, 그리고 서버측에서도 방지를 해준다면 사용자 경험, 서버는 자원을 아낄 수 있다고 생각합니다.
아래에 그 해결책이 있습니다.
ps. 뒤로가기 앞으로가기 버튼으로 막는것은 실무에서 사용하는 시스템과 상황에따라 다를 수 있습니다.
![]() | 첫번째 주문 요청시 DB에 주문 데이터를 저장하고, 응답메시지를 200이 아닌 302 리다이렉션으로 줍니다. 물론 303도 가능합니다. HTTP 메서드가 GET으로 변경되면서 새로고침을 하여도 주문데이터 조회만 가능할 뿐 (멱등성) POST 메서드가 요청되어서 중복주문되는 상황을 방지할 수 있습니다. |
|---|
정리
개발 역사
현실
300 Multiple Choices : 안씁니다.
304 Not Modified ( 정말 많이 사용합니다. )
클라이언트의 요청에 잘못된 문법등으로 서버가 요청을 수행할 수 없습니다.
오류의 원인이 클라이언트에 있습니다.
클라이언트가 이미 잘못된 요청, 데이터를 보내고있기 때문에 같은 요청을 재시도해도 실패합니다.
![]() 클라이언트가 잘못된 요청을 했을 때 발생합니다. ( 서버가 요청을 처리할 수 없을 때 ) ex) 문자로 보내야하는데, 숫자를 보내거나 요청 자체가 잘못됐을 때 | ![]() |
|---|
![]() | ![]() |
|---|
서버 문제로 오류 발생
오류의 원인이 서버에 있습니다.
클라이언트가 알맞은 요청을 보내도 오류로 응답할 수 있고, 서버가 복구되거나 했을때 같은 요청을 재시도하면 성공할 수도 있습니다.
![]() | ![]() |
|---|
설명이 섹시하네요.