2025. 3. 25. 22:31ㆍ기반기술/서버 개발
본 게시글은 아래의 강의를 수강하고 요약 및 추가 정리한 게시글 입니다.
모든 개발자를 위한 HTTP 웹 기본 지식 강의 | 김영한 - 인프런
김영한 | , [사진] 📣 확인해주세요!본 강의는 자바 스프링 완전 정복 시리즈의 세 번째 강의입니다. 우아한형제들 최연소 기술이사 김영한의 스프링 완전 정복 로드맵을 먼저 확인해주세요. (바
www.inflearn.com
[목차]
1. 인터넷 네트워크
2. URI와 웹 브라우저 요청 흐름
--------------------------------- 포스팅 (1)
3. HTTP 기본
4. HTTP 메서드
5. HTTP 메서드 활용
6. HTTP 상태 코드
--------------------------------- 포스팅 (2) ← 이번 포스팅
7. HTTP 헤더 - 일반 헤더
8. HTTP 헤더 - 캐시와 조건부 요청
--------------------------------- 포스팅 (3)
3. HTTP 기본
3-1. 모든 것이 HTTP
- HTTP: HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜
- HTTP/HTTPS는 주로 웹 브라우저와 서버 사이의 통신에 사용되는 프로토콜이다.
서버 간에 데이터를 주고 받을 때도 대부분 HTTP를 사용함 - 지금은 HTTP 시대. 단순하지만 확장가능한 기술
- HTTPS는 HTTP에 보안(Security)을 추가한 형태
- 데이터베이스와 애플리케이션 간에 SQL 쿼리를 주고받을 때 MySQL 프로토콜이 사용되는 등 각각의 필요에 맞는 프로토콜이 존재함
- HTTP/HTTPS는 주로 웹 브라우저와 서버 사이의 통신에 사용되는 프로토콜이다.
- HTTP 메시지에 거의 모든 형태의 데이터를 담아 전송할 수 있음
- HTML, TEXT
- 이미지, 음성, 영상, 파일
- JSON, XML (-> API 필요)
- HTTP 역사
종류 | 개발 년도 | 특징 | 기반 프로토콜 |
HTTP/0.9 | 1991년 | GET 메서드만 지원, HTTP 헤더 X | |
HTTP/1.0 | 1996년 | 메서드, 헤더 추가됨 | |
HTTP/1.1 | 1997년 | 가장 많이 사용됨, 우리에게 가장 중요한 버전 RFC2068 (1997) -> RFC2016 (1999) -> RFC7230~7235(2014) |
TCP |
HTTP/2 (h2) | 2015년 | 1.1에서 성능 개선에 초점을 맞춘 버전 | TCP |
HTTP/3 (h3) | 진행중 | TCP 대신에 UDP 사용, 성능 개선 | UDP |
- HTTP 특징
- 클라이언트-서버 구조
- 무상태 프로토콜, 비연결성
- HTTP 메세지
- 단순함, 확장 가능
3-2. 클라이언트-서버 구조
- HTTP는 클라이언트와 서버 사이의 통신에 사용되는 프로토콜로 Request-Resonse 구조이다.
- 클라이언트가 서버에 요청 -> 응답 대기
- 서버가 요청에 대한 결과를 만들어서 클라이언트에 응답
- 클라이언트-서버 구조의 장점: 양 쪽이 각자의 할 일을 맡아 독립적으로 진화할 수 있다.
- 클라이언트: 화면을 그리는데 집중
- 서버: 복잡한 비지니스 로직과 데이터 처리에 집중
3-3. Stateful, Stateless
- 무상태 프로토콜(Stateless)
- 서버가 클라이언트의 상태를 보존하지 않는다.
- 장점: 서버 확장성 높음 (스케일 아웃, 서버 수평 확장) -> 대용량 트래픽 대응에 유리함
- 단점: 클라이언트가 추가 데이터를 전송해야함
- Stateful(상태 유지)와 Stateless(무상태) 예시로 이해
- Stateful : 고객과 점원이 기존 대화의 맥락을 가지고 대화함. 그러나 만약 점원이 바뀌면 에러됨.
노트북 얼마에요? 점원A: 100만원이요 (노트북 상태 유지) -> 2개 살게요. 점원A: 200만원 입니다 (노트북, 2개 상태 유지)
노트북 얼마에요? 점원A: 100만원이요 -> 2개 살게요. 점원B: 네? 어떤걸 2개? (이전의 노트북 상태 유지 X, 오류) - Stateless : 고객이 말 할 때마다 점원이 바뀐다는 것을 인지하고 대화함. 계속 예전에 했던 얘기를 갱신해서 얘기해준다.
노트북 얼마에요? 점원A: 100만원이요 -> 노트북을 2개 살게요. 점원B: 네 200만원입니다.
- Stateful : 고객과 점원이 기존 대화의 맥락을 가지고 대화함. 그러나 만약 점원이 바뀌면 에러됨.
- Stateful(상태 유지)와 Stateless(무상태) 차이 정리
- 상태 유지: 클라이언트-서버가 맥락을 가지고 통신하기 때문에 항상 같은 서버가 유지 되어야한다. 중간에 서버가 바뀌면 상태가 끊기면서 오류 발생.
- 무상태: 클라이언트-서버가 이번 응답에 필요한 정보를 요청에 모두 담아서 보내므로 중간에 다른 서버로 바뀌어도 된다.
즉 무상태는 응담 서버를 쉽게 바꿀 수 있으므로 서버 무한 증설 가능, 서버 장애에 유연하게 대응 가능
- 무상태 실무 한계
- 모든 것을 무상태로 설계할 수 있는 것은 아니다.
- 로그인한 사용자의 경우 로그인 했다는 상태를 서버에 유지해야 하기 때문에 일반적으로 브라우저 쿠키, 서버 세션을 사용해서 상태를 유지한다.
- 단, 상태 유지는 꼭 필요한 경우에 최소한만 사용하는 것이 권장된다.
3-4. 비연결성 (Connectionless)
- HTTP는 클라이언트가 요청하고 서버가 이에 대해 응답하면 TCP/IP 연결을 바로 종료시킨다.
- 일반적으로 현재 수천명이 서비스를 사용하고 있는 상황이어도 실제 서버에서 동시에 처리해야하는 요청은 수십개 이하로 적다.
- 장점: 서버가 연결을 유지할 필요 없기 때문에 서버 자원을 효율적으로 사용할 수 있다.
- 단점
- 요청마다 계속 TCP/IP 연결을 새로 맺어야 하기 때문에 응답에 걸리는 시간이 추가됨
- 한번 요청하면 HTML, JS, CS, 추가 이미지 등의 자원이 함께 다운로드 되는데 연결을 끊으면 계속 다시 다운로드 해야함
- 해결 방안 : HTTP 지속 연결
- HTTP/2, HTTP/3에서 이에 대해 더 많은 최적화가 이루어짐
- 내부 메커니즘으로 HTTP 지속 연결을 진행하여 연결-종료 낭비 해결
3-5. HTTP 메시지
1) 시작 라인 (start-line)
- 요청 시작 라인: request-line = method SP(공백) request-target SP HTTP-version CRLF(엔터)
- HTTP 메서드: 서버가 수행해야 하는 동작 지정, GET/POST
- 요청 대상(request-target): /로 시작하는 절대경로[?쿼리]
- 응답 시작 라인: status-line = HTTP-version SP status-code SP reason-phrase CRLF
- HTTP 상태코드: 요청 성공, 실패를 나타냄
200-성공, 400-클라이언트 요청 오류, 500-서버 내부 오류 - 이유 문구: 상태코드에 대한 짧은 설명 글 (보는 사람이 이해할 수 있게)
- HTTP 상태코드: 요청 성공, 실패를 나타냄
2) 헤더 (header)
- header-field = field-name ":" OWS(띄어쓰기 허용) field value OWS
- field-name은 대소문자 구분X, field value는 당연히 구분O
- http 전송에 필요한 모든 부가 정보가 다 들어가 있음
- 표준 헤더 필더가 너무 많음
3) 메세지 바디 (message body)
- 실제로 전송할 데이터
- HTML 문서, 이미지, 영상, JSON 등등 byte로 표현할 수 있는 모든 데이터를 전송할 수 있다.
4. HTTP 메서드
4-1. HTTP API를 만들어보자 - API URI 설계
1) 회원 정보 관리 API를 만들어보자
기능: 회원 목록 조회 • 회원 조회 • 회원 등록 • 회원 수정 • 회원 삭제
2) API URI 설계
- URI 설계에서 가장 중요한 것은 리소스 식별
- '리소스'와 해당 리소스를 대상으로 하는 '행위'을 분리해야 한다.
- 즉 조회, 등록, 수정, 삭제의 행동(→동사)은 모두 배제하고
'회원'이라는 리소스(→명사)만 식별하여 URI에 매핑한다. - URI 설계 비교
기능 | 리소스와 행위 분리하지 않은 URI 설계 | 리소스와 행위 분리한 URI 설계 |
회원 목록 조회 | /read-member-list | /members |
회원 조회 | /read-member-by-id | /members/{id} |
회원 등록 | /create-member | /members/{id} |
회원 수정 | /update-member | /members/{id} |
회원 삭제 | /delete-member | /members/{id} |
- 그렇다면 이처럼 리소스만 식별하는 URI는 행위를 어떻게 구분해야 할까? → HTTP 메서드!
- 컨트롤 URI
- 단, 모든 URI를 리소스 식별만으로 설계할 수는 없고 기능적인 행위를 포함하는 URI도 있음
- 예) POST/orders/{orderID}/start-delivery → 배달 시작이라는 기능을 위해 start-delivery라는 행위 포함됨
4-2. HTTP 메서드
1) HTTP 메서드
- HTTP 메서드는 리소스를 식별하는 URI의 행위를 나타내준다.
- 클라이언트가 서버에게 요청할 때 기대하는 행위
클라이언트: 서버야, 이러이러한 행위를 해주렴 - HTTP 메서드 종류
- GET: 리소스 조회
- POST: 요청 데이터 처리, 주로 등록에 사용
- PUT: 리소스를 대체, 해당 리소스가 없으면 생성
- PATCH: 리소스 부분 변경
- DELETE: 리소스 삭제
- 기타: HEAD, OPTIONS, CONNECT, TRACE
2) GET : 리소스 조회
- 서버에 요청 데이터 전달하는 방법: 쿼리(쿼리 파라미터, 쿼리 스트링)를 통해서 전달
- GET도 메시지 바디를 사용해서 데이터를 전달할 수 있지만, 지원하지 않는 곳이 많아서 권장하지는 않음
- 단, GET으로 보내면 서버에서 캐싱을 하기 때문에 조회 요청은 최대한 GET으로 보내는 것이 좋음
3) POST : 요청 데이터 처리
- 서버에 요청 데이터 전달하는 방법 : HTTP 요청 메시지의 메시지 바디를 통해서 전달
- POST 요청에는 딱 정해져 있는 행위가 없기 때문에, 리소스 마다 POST 요청 데이터를 어떻게 처리할지 정해둬야함
- POST 요청은 서버에서 신규 리소스 식별자를 생성한다 (/members -> /members/100)
- 서버는 메시지 바디를 통해 들어온 데이터를 처리하는 모든 기능을 수행한다.
- 새 리소스 생성
- 요청 데이터 처리
- 다른 메서드로 처리하기 애매한 경우 (조회 데이터를 JSON으로 넘길때 등)
- POST 요청에는 딱히 정해져 있는 행위가 없기 때문에, 리소스 마다 POST 요청 데이터를 어떻게 처리할지 다 따로 정해둬야한다.
4) PUT : 리소스 완전 대체
- 리소스가 있으면 지우고 새 걸로 대체, 없으면 생성 → 덮어버림
- PUT은 기존 리소스 삭제하고 완전히 대체한다. 부분 수정은 PATCH
- POST와의 차이: 클라이언트가 리소스를 식별한다. 클라이언트가 리소스 위치를 알고 URI를 지정함.
- POST: 클라이언트 /members → 서버 /members/100
- PUT: 클라이언트 /members/100
5) PATCH : 리소스 부분 변경
- 리소스의 age만 변경, 나머지는 그대로
6) DELETE : 리소스 제거
4-3. HTTP 메서드의 속성
1) 안전 (Safe Methods)
- 호출해도 해당 리소스를 변경하지 않는다.
2) 멱등 (Idempotent Methods)
- 한 번 호출하든 100번 호출하든 결과가 똑같다.
단, 외부 요인으로 중간에 리소스가 변경되는 것 까지는 고려하지 않는다. (중간에 데이터 변경되면 조회결과 달라지는거 아닌가? 등은 고려하지 않음) - 멱등 메서드
- GET : 한번 조회하든, 100번 조회하든 같은 결과가 조회된다.
- PUT : 결과를 완전히 대체하기 때문에 여러번 요청해도 같은 결과가 조회된다.
- DELETE : 같은 데이터를 여러번 삭제해도 삭제 됐다는 결과는 똑같다.
- POST : 멱등하지 않음! 같은 데이터로 결제 2번 하면, 중복 결제 오류가 날 수 있음.
- 왜 멱등이라는 속성이 필요한가?
- 자동 복구 메커니즘
- 서버가 TIMEOUT 등으로 정상 응답을 주지 못했을 때, 클라이언트가 같은 요청을 다시 해도 괜찮은가?를 판단하는 근거가 된다.
3) 캐시가능 (Cacheable Methods)
- 응답 결과 리소스를 캐시해서 사용해도 되는가?
- GET, HEAD, POST, PATCH 캐시 가능
- 그러나 실제로는 GET, HEAD 정도만 캐시로 사용한다. (본문 내용까지 캐시 키 구현이 쉽지 않음)
5. HTTP 메서드 활용
5-1. 클라이언트에서 서버로 데이터 전송 상황 4가지
클라이언트 → 서버 데이터 전송 방식 | HTTP 메서드 | 용도 |
쿼리 파라미터를 통한 데이터 전송 | GET | 조회, 주로 정렬 필터 (검색어) |
HTTP 메시지 바디를 통한 데이터 전송 | POST, PUT, PATCH | 회원 가입, 상품 주문, 리소스 등록, 리소스 변경 |
1) 정적 데이터 조회: 이미지, 정적 텍스트 문서 등
- GET - 쿼리 파라미터 미사용
2) 동적 데이터 조회: 주로 게시판 목록에서 정렬 필터
- GET - 쿼리 파라미터 사용
- 서버에서 쿼리 파라미터를 기반으로 정렬 필터해서 결과를 동적으로 생성한다.
3) HTML Form을 통한 데이터 전송
- 회원가입, 상품주문, 데이터 변경
- POST와 GET 방식만 가능
단, GET은 조회에서만 사용 가능! 리소스 변경이 발생하는 곳에서는 사용하면 안 됨. - Content-Type: 메시지 바디에 담기는 데이터의 타입을 기재
- Content-Type: application/x-www-form-urlencoded
- form의 내용을 쿼리 파라미터 형식(key=value)으로 변환하여 메시지 바디를 통해서 전송
- 전송 데이터를 url encoding 처리
- Content-Type: multipart/form-data
- 파일 업로드 같은 바이너리 데이터 전송시 사용
- 다른 종류의 여러 파일과 폼의 내용 함께 전송 가능(그래서 이름이 multipart)
4) HTTP API를 통한 데이터 전송
- HTML form을 쓰지 않고 메시지 바디로 데이터를 주고 받는 모든 상황
- 서버 → 서버: 백엔드 시스템 통신
- 앱 클라이언트: 아이폰, 안드로이드
- 웹 클라이언트: HTML이지만 Form 전송이 아닌 자바 스크립트를 통한 비동기 통신에 사용(AJAX)
예) React, VueJs 같은 웹 클라이언트와 API 통신
- POST, PUT, PATCH: 메시지 바디를 통해 데이터 전송
GET: 조회, 쿼리 파라미터로 데이터 전달 - Content-Type: application/json
메시지 바디에 담기는 데이터의 형식은 대부분 JSON으로 사용된다 (TEXT, XML, JSON 등이 있지만 JSON이 사실상 표준)
5-2. HTTP API 설계 예시
1) HTTP API - 컬렉션: POST 기반의 신규 자원 등록
- 회원 관리 시스템과 같은 경우 신규 자원 등록시 POST를 사용한다.
- POST의 특징: 클라이언트는 등록될 리소스의 URI를 모르고, 서버가 새로 등록된 리소스 URI를 생성해준다.
요청: POST /members → 응답: Location: members/100 - 컬렉션(Collection): 서버가 관리하는 리소스 디렉토리 (대부분 이걸 사용함)
여기서 컬렉션은 /members
2) HTTP API - 스토어: PUT 기반의 신규 자원 등록
- 정적 컨텐츠, 파일 관리 시스템 등의 경우에는 신규 자원 등록시 PUT을 사용한다. (덮어씌우기)
- PUT의 특징: 클라이언트가 직접 리소스 URI 알고 지정한다.
요청: PUT /files/star.jpg - 스토어(Store): 클라이언트가 관리하는 리소스 저장소
여기서 스토어는 /files
3) HTML FORM 사용: GET, POST만 지원
- 순수 HTML + HTML form만 사용하는 경우 GET과 POST만 사용 가능
- 회원 등록 폼 화면으로 이동하는 url : /members/new -> GET 방식
회원 등록 URI : /members/new -> POST 방식 - 컨트롤 URI 사용
- http form은 GET과 POST 방식만 지원하기 때문에 동사로 된 리소스 경로, 컨트롤 URI를 사용해야함
- POST의 /new, /edit, /delete가 컨트롤 URI
- HTTP 메서드나 HTTP API로 해결하기 애매한 경우에 사용한다. 실무에서 많이 쓰임.
5-3. 참고하면 좋은 URI 설계 개념 정리
1) 문서(document)
- 단일 개념: 파일 하나, 객체 인스턴스, 데이터베이스 row
- 예) /members/100, /files/star.jpg
2) 컬렉션(collection)
- 서버가 관리하는 리소스 디렉터리
- 서버가 리소스의 URI를 생성하고 관리
- 예) /members
3) 스토어(store)
- 클라이언트가 관리하는 자원 저장소
- 클라이언트가 리소스의 URI를 알고 관리
- 예) /files
4) 컨트롤러(controller), 컨트롤 URI
- 문서, 컬렉션, 스토어로 해결하기 어려운 추가 프로세스 실행
- 동사를 직접 사용
- 예) /members/{id}/delete
6. HTTP 상태 코드
6-1. HTTP 상태 코드 개요
- 상태 코드: 클라이언트가 보낸 [요청]의 처리 상태를 [응답]에서 알려주는 기능
- 상태 코드의 종류
상태 코드 | 요약 | 설명 |
1xx | Informational | 요청이 수신되어 처리 중 (거의 사용되지 않음) |
2xx | Successful | 요청 정상 처리 |
3xx | Redirection | 요청을 완료하려면 추가적인 행동이 필요 |
4xx | Client Error | 클라이언트 오류, 잘못된 문법 등으로 서버가 요청을 수행할 수 없음 클라이언트 측의 잘못된 요청이기 때문에 재시도를 해도 똑같이 계속 실패함 |
5xx | Server Error | 서버 오류, 서버가 정상 요청을 처리하지 못함 서버 문제이기 때문에 재시도 하면 성공할 수도 있음 (서버 복구됨 등) |
- 만약 서버가 클라이언트가 모르는 상태 코드를 반환하면?
클라이언트는 상위 상태 코드로 해석해서 처리함. 예: 299? -> 2xx (Successful)
6-2. 세부 상태코드
- 2xx: 성공
- 200 : OK
- 201 : Created
- 202 : Accepted, 접수는 되었으나 아직 처리가 완료되진 않음 (배치 등)
- 204 : No Content, 요청은 성공적이지만 본문에 보낼 데이터가 없음
- 3xx: 리다이렉션
- 300 : Multiple Choices
- 301 : Moved Permanently
- 302 : Found
- 303 : See Other
- 304 : Not Modified
- 307 : Temporary Rediect
- 307 : Permanent Rediect
- 4xx: 클라이언트 오류
- 400 Bad Request : 요청 파라미터, API 스펙이 맞지 않을 때 등
- 401 Unauthorized: 클라이언트가 해당 리소스에 대한 인증이 필요함
- 인증(Authentication): 본인이 누구인지 확인
- 인가(Authorization): 권한 부여 (인증 -> 인가)
- 오류 메시지가 Unauthorized이지만 인증 문제이기 때문에 이름이 아쉬움
- 403 Forbidden: 서버가 요청을 이해 했지만, 승인을 거부함
주로 인증 자격 증명은 있지만, 접근 권한이 불충분한 경우 (admin 권한 없음 등) - 404 Not Found: 요청한 리소스가 서버에 없음, 또는 해당 리소스를 숨기고 싶을 때
- 5xx: 서버 오류
- 500 Internal Server Error : 서버 문제로 오류 발생, 애매하면 500
- 503 Service Unavailable : 서버가 일시적인 과부하 또는 예정된 작업으로 잠시 요청을 처리할 수 없음
- 5xx 에러는 정말 서버에 예상치 못한 문제가 있었을 때만 내는 것이고 에러와 예외 케이스를 헷갈리면 안된다.
예외 케이스는 정상 프로세스이므로 서버 에러가 아닌 다른 과정이 필요함.
6-3. 리다이렉션
1) 리다이렉션: 웹 브라우저는 3xx 응답의 결과에 Location 헤더가 있으면, Location 위치로 자동으로 이동한다
2) 리다이렉션 종류
- 영구 리다이렉션 (301, 308)
- 특정 리소스의 URI가 영구적으로 이동, 예) /member -> /users
- 원래의 URL 사용X, 검색 엔진 등에서도 변경 인지
- 301 Move Permanently: 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음
- 308 Rermanent Redirect: 리다이렉트시 요청 메서드와 본문을 유지 (처음 POST면 유지)
- 일시 리다이렉션: 일시적인 변경 (302, 307, 303)
- 리소스의 URI가 일시적으로 변경
예) 주문 완료 후 주문 내역 화면으로 이동, PRG(Post/Redirect/Get) - 따라서 검색 엔진 등에서 URL을 변경하면 안됨
- 302 Found: 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음 -> 이게 주로 디폴트로 설정 되어있음
- 307 Tempory Redirect: 리다이렉트시 요청 메서드와 본문 유지
- 303 See Other: 리다이렉트시 요청 메서드가 GET으로 변경
- 그래서 뭘 쓰라는? 처음 302의 의도는 HTTP 메서드를 유지하는 것이었지만, 웹 브라우저들이 대부분 GET으로 바꾸어버리고 일부는 다르게 동작하는 등 모호하게 동작함 -> 모호한 302 대신 명확한 307, 303이 등장 -> 그래서 307, 303을 권장하지만, 이미 거의 302를 기본 값으로 사용하므로 GET으로 바뀌어도 되면 302 써도 됨
- 리소스의 URI가 일시적으로 변경
- 특수 리다이렉션: 결과 대신 캐시 사용 (304)
3) PRG: Post/Redirect/Get 예시
- PRG 사용 전: POST로 주문 후 현재 URI 그대로 응답을 하는 경우, 결과 화면에서 새로고침을 하면 중복 주문이 이루어지는 문제 발생
- PRG 사용 후: POST로 요청 된 주문의 결과 화면을 GET 메서드로 리다이렉트하면, 새로고침해도 중복 주문이 이루어지지 않고 결과 화면만 다시 GET으로 다시 요청된다.