서버와 클라이언트의 약속, HTTP

요청에요청을F12 클릭시 Transaction , HTTP 헤더 분석

  • Headers : HTTP 헤더에 대한 정보를 보여 준다. 요청에 대한 헤더와 응답에 대한 헤더를 나눠서 볼 수 있다.

  • Payload : Payload 라는 용어 자체가 데이터 전송에 포함되는 내용의 데이터를 의미한다. HTTP 요청은 헤더(header)와 바디(Body) 부분으로 나뉘므로 요청의 바디에 해당하는 데이터가 있는 경우에는 해당 탭에서 확인 가능하다. 현재 www.google.com에 접속할 때는 요청의 바디가 없기 때문에 탭이 보이지 않는 것이다.

  • Preview : 응답의 바디에 포함된 데이터를 보기 좋은 형태의 미리보기로 제공한다. 앞서 JSON 데이터를 자바스크립트 객체 형태로 보여 줬던 것이 이 탭에 해당된다. 만약 응답의 바디에 HTML 문서가 있다면 웹 브라우저에 보이는 것처럼 미리보기할 수 있다. 이미지 파일 역시 여기서 볼 수 있다.

  • Response : [Preview] 탭과 동일하게 응답의 바디에 포함된 데이터를 보여 주지만, 있는 그대로 보여준다. JSON 문자열을 그대로 보거나 HTML 문서를 그대로 볼 수 있다. 마찬가지로 이미지 파일도 바이너리 데이터로 보여줄 것같지만, 바이너리 데이터로 보여주지않고 this request has no response data available이라는 문구가 나온다.

  • initiater

  • Timing

  • Cookies

HTTP 트랜잭션은 HTTP 요청과 응답이 하나의 묶음으로 이루어진다는 의미를 가지고 있지만 일반적으로 사용되는 트랜잭션이라는 표현은 보통 쪼개질 수 없는 처리를 의미한다.

HTTP의 특징

HTTP/1.1 버전에 기반한 HTTP의 대표적 특징

  • HTTP는 클라이언트의 요청으로 HTTP 트랜잭션이 시작된다. HTTP의 등장 초기에는 단순히 HTTP 문서 하나에 대한 HTTP 요청이 주를 이루었지만, 점점 다양한 서비스 요구사항에 의해 다양한 형태로 서버의 리소스를 제공하게 되었다. 클라이언트가 먼저 요청을 시작한다는 HTTP의 특징은 서버에서 데이터를 줘야 할 때 실시간으로 줄 수 없다는 한계가 있어 웹 소켓과 같은 기술이 도입되기도 했다.

  • HTTP는 상태를 가지지 않는다. 쉽게 이야기 하면 이전 HTTP 트랜잭션과 다음 HTTP 트랜잭션 사이에 연관 관계가 없다. 서버는 지금 요청을 한 클라이언트와 잠시 후 요청한 클라이언트가 설령 같은 클라이언트라고 하더라도 구분할 수 없다. 이러한 특징을 HTTP는 무상태성이다 라고 표현한다.

  • HTTP는 비연결성을 갖는다.

    • HTTP는 데이터를 주고 받기 위해 연결이라는 과정이 필요하고 ,HTTP 트랜잭션이 종료되면 연결을 끊어 버린다.

    • 장점으로는 클라이언트와 서버의 자원을 효율적으로 사용할 수 있다.

    • 단점으로는 매번 HTTP 트랜잭션마다 연결을 맺고 끊는 과정이 추가되어야 한다.

HTTP keep-alive, TCP keep-alive

좋습니다! 많이 헷갈리는 부분인 HTTP Keep-Alive vs TCP Keep-Alive 차이점과, “같은 연결인지 어떻게 구분하는가?” 에 대한 질문도 함께 정확하게 정리해드릴게요.


✅ 1. HTTP Keep-Alive vs TCP Keep-Alive

항목

HTTP Keep-Alive

TCP Keep-Alive

계층

애플리케이션 계층 (HTTP)

전송 계층 (TCP)

목적

같은 HTTP 연결을 여러 요청에 재사용

오랫동안 사용하지 않은 TCP 연결이 죽었는지 확인

기본 사용 대상

브라우저 ↔ 서버 간 다수의 HTTP 요청/응답

서버 ↔ 클라이언트 간 장기 연결 (예: WebSocket, DB)

설정 위치

HTTP 헤더 (Connection, Keep-Alive)

OS 소켓 설정 (SO_KEEPALIVE)

감지 방식

타임아웃 or 요청 없음

정기적으로 keepalive probe 패킷 전송

주요 사용처

웹 페이지 로딩 속도 최적화

네트워크 장애/세션 만료 감지


예시로 쉽게 설명하면:

  • HTTP Keep-Alive: “이 커피숍 자리 계속 쓸게요. 또 주문할 거니까 자리 비우지 말아줘요.”

  • TCP Keep-Alive: “상대방이 여전히 살아있는지 주기적으로 손 흔들어봐요. 응답 없으면 끊자.”


✅ 2. "같은 연결"은 어떻게 구분하나? (by TCP)

TCP 연결은 다음 4가지 값으로 고유하게 구분됩니다:

항목
설명

① 클라이언트 IP 주소

요청 보낸 쪽

② 클라이언트 포트 번호

임시 포트 (ephemeral port)

③ 서버 IP 주소

수신 측 주소

④ 서버 포트 번호

예: 80, 443 등 서비스 포트

이 네 가지를 묶어 TCP 연결의 고유 ID라고 부릅니다. 그래서 IP 주소만 같다고 해서 같은 연결이 절대 아닙니다!


🔎 예시

클라이언트
서버
구분

192.168.1.10:54000 → 93.184.216.34:80

연결 A

192.168.1.10:54001 → 93.184.216.34:80

연결 B (다름)

192.168.1.10:54000 → 93.184.216.34:443

연결 C (다름)

  • IP 같아도 포트가 다르면 다른 연결

  • HTTP Keep-Alive는 같은 TCP 연결(4개 조합 동일) 내에서만 유효


✅ 정리 요약

질문
답변

HTTP Keep-Alive

HTTP 요청을 동일 TCP 연결에서 반복해서 보내는 기능

TCP Keep-Alive

오랫동안 활동이 없는 TCP 연결이 살아 있는지 확인하는 기능

같은 연결인지 어떻게 구분?

(클라이언트 IP, 클라이언트 포트, 서버 IP, 서버 포트)의 조합으로 식별됨


✅ 부가 팁

  • TCP Keep-Alive는 운영체제 소켓 설정으로 제어 (TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT)

  • HTTP Keep-Alive는 브라우저/서버 설정에 따라 제한된 요청 수(max) 또는 시간(timeout) 후 종료

  • HTTP/2에서는 단일 연결 멀티 요청(멀티플렉싱) 이므로 Keep-Alive 개념보다 스트림 관리가 핵심


필요하시면:

  • 리눅스에서 netstat으로 연결 구분 보기

  • Spring Boot에서 Keep-Alive 설정

  • Nginx reverse proxy Keep-Alive 구성

도 바로 이어서 알려드릴 수 있어요!

HTTP 1.1 외의 버전

  • HTTP 0.9 버전

    • 단순히 GET이라는 하나의 메서드만 지원

  • HTTP 1.0

    • POST와 HEAD 메서드, 상태 코드와 여러 가지 헤더 추가

  • HTTP 1.1

    • 커넥션에 대한 지속적인 연결(Persistent Connections)가 추가됨

HTTP 2 버전

  • 하나의 커넥션에서 여러 개의 요청을 동시에 다중(Multiplex) 처리할 수 있다.

  • 헤더를 압축한다.

  • 서버에서 예상되는 요청을 미리 클라이언트에 전송한다.

  • 웹 브라우저로 웹 서핑을 하면 하나의 HTML 페이지를 먼저 다운로드하고 거기에 포함된 여러 개의 CSS, 자바스크립트, 이미지 파일을 연달아 받는 상황이 흔히 발생한다. 이런 상황에서 HTTP/1.1 은 파이프라이닝이라는 방법으로 하나의 커넥션을 통해 요청과 응답을 처리하도록 개선했다. 그러나 여기에는 반드시 '요청한 순서와 동일하게 응답이 와야 한다' 라는 제약이 있어, 앞쪽 요청에 대한 처리가 늦어지면 뒤쪽 요청에 대한 처리 역시 늦어진다는 문제가 있었다. HTTP/2 는 다중화를 통해 요청한 순서에 상관없이 응답이 오는 대로 처리할 수 있도록 개선했다.

HTTP2

좋습니다! HTTP/2가 어떻게 다중화(multiplexing)를 통해 성능을 개선했는지, 그리고 그 원리를 차근차근 설명드릴게요.


✅ 먼저, HTTP/1.1의 문제점

🔸 HTTP/1.1의 주요 한계

문제
설명

💥 연결당 하나의 요청/응답

같은 연결에서 여러 요청을 병렬로 보내면 응답이 순차적으로 와야 함 (head-of-line blocking 발생)

🔀 다중 연결 필요

브라우저는 이를 우회하기 위해 TCP 연결을 여러 개 열어야 함 (6개 정도 제한)

📦 헤더 중복

매 요청마다 큰 헤더를 반복해서 전송 (예: Cookie, User-Agent)

🕒 지연 많음

연결 설정 + 요청 순차 처리로 인해 지연 발생


✅ HTTP/2의 핵심 개선: Multiplexing (다중화)

📌 원리 요약

하나의 TCP 연결 위에서 여러 요청/응답을 병렬로 동시에 주고받을 수 있음


🧠 작동 원리 (HTTP/2 내부 구조)

1. Stream (스트림)

  • 하나의 요청-응답 쌍 = 하나의 스트림

  • 각 스트림은 고유한 ID로 식별됨

2. Frame (프레임)

  • 스트림은 작은 단위의 프레임으로 쪼개져 전송

  • 프레임은 스트림 ID를 포함하여, 서로 섞여도 구분 가능

예: 클라이언트가 스트림 1로 HTML, 스트림 3으로 JS, 스트림 5로 CSS 요청 → 서버는 각 응답을 나눠서 동시에 보냄, TCP 혼합 전송 가능

3. Multiplexing

  • 여러 스트림의 프레임을 하나의 TCP 연결에 섞어 전송

  • 병렬 요청 처리 가능 (→ 순서 의존성 없음)

  • 브라우저는 응답 순서를 기다릴 필요 없음


✅ 시각적 비교

🔸 HTTP/1.1

[TCP 연결 1] → 요청1 → 응답1 → 요청2 → 응답2 ...
(head-of-line blocking 발생)

→ 병렬 요청하려면 TCP 연결을 여러 개 열어야 함

🔸 HTTP/2

[TCP 연결 1]
→ 스트림1: 요청1-응답1
→ 스트림2: 요청2-응답2
→ 스트림3: 요청3-응답3
(모든 요청/응답이 동시에, 순서 없이 흐름에 따라 전달)

✅ HTTP/2의 다른 특징도 함께

기능
설명

헤더 압축 (HPACK)

중복되는 헤더를 압축하여 전송량 감소

서버 푸시 (Server Push)

클라이언트가 요청하지 않아도 서버가 자원 미리 전송 가능

단일 연결 사용

하나의 TCP 연결만 유지 → 연결 오버헤드 감소

우선순위

스트림에 우선순위를 설정하여 중요한 자원 먼저 전송 가능


📌 하지만 단점도 있음: TCP Head-of-Line Blocking (TCP HoLB)

  • 하나의 TCP 연결에 모든 요청이 몰림

  • TCP 레벨에서 패킷 손실 발생 시, 전체 프레임 흐름이 지연됨

  • 이 문제는 HTTP/3(QUIC 기반) 에서 해결됨


✅ 한 줄 요약

HTTP/2는 하나의 TCP 연결에서 프레임 기반의 다중 스트림(multiplexing) 을 사용하여, 여러 요청/응답을 동시에, 병렬로, 헤더 압축까지 적용해 성능을 획기적으로 개선한 프로토콜입니다.


HTTP2 frame 조립 일어나는 곳

✅ 먼저 용어 정리

용어
설명

Connection

하나의 TCP 연결

Stream

하나의 요청-응답 흐름 (고유 ID로 식별됨)

Frame

스트림을 구성하는 최소 단위. 실제 데이터가 담김

Multiplexing

여러 스트림의 프레임을 하나의 연결로 섞어서 전송


✅ HTTP/2 스트림 구조

HTTP/2에서는 모든 메시지가 프레임(Frame) 으로 나뉘어 전송됩니다.

🔹 Frame 종류

종류
설명

HEADERS

요청/응답 헤더

DATA

본문 (Payload)

SETTINGS

연결 설정

WINDOW_UPDATE

흐름 제어

PRIORITY

스트림 우선순위 지정

RST_STREAM

스트림 강제 종료

PUSH_PROMISE

서버 푸시


✅ 실제 구조 예시

브라우저가 HTTP/2로 아래 요청들을 보낸다고 가정:

  • 요청1: HTML 요청

  • 요청3: CSS 요청

  • 요청5: JS 요청

1. 요청 프레임

scss복사편집[Stream 1]
  → HEADERS frame (GET /index.html)
[Stream 3]
  → HEADERS frame (GET /style.css)
[Stream 5]
  → HEADERS frame (GET /script.js)

2. 응답 프레임 (섞여서 오지만 ID로 구분)

less복사편집→ HEADERS (stream:1) → DATA (stream:3) → DATA (stream:1) → DATA (stream:5) ...

프레임 순서가 뒤섞여도, 각 프레임에는 Stream ID 가 있으므로 브라우저는 재조립해서 처리할 수 있습니다.


🧪 Wireshark로 보기 (실제 확인 방법)

1. Wireshark 설치 후 HTTP/2 트래픽 캡처

필터 입력:

nginx복사편집http2

2. 프레임 확인

  • 패킷 상세보기에서:

    yaml복사편집Hypertext Transfer Protocol 2
      Stream Identifier: 3
      Type: HEADERS (0x1)
      Length: 156
      ...
  • 각 프레임에 Stream ID, Type, Length 가 표시됨

  • 여러 Stream ID가 번갈아 나타나는 것을 확인 가능 → multiplexing 실제 확인 가능


✅ 시각적 구조 요약

arduino복사편집[ TCP 연결 ]
   ├─ Stream 1: HEADERS → DATA → DATA ...
   ├─ Stream 3: HEADERS → DATA ...
   ├─ Stream 5: HEADERS → DATA → RST_STREAM
  • 각 스트림은 자체적으로 요청/응답 흐름 유지

  • 프레임 단위로 쪼개져 TCP를 통해 전달 → 혼합 가능

  • HTTP/1.1처럼 하나 끝나야 다음 시작 구조가 아님


✅ 결론

HTTP/2 스트림 구조는 "프레임 단위 전송"과 "스트림 ID 구분"을 통해, 하나의 TCP 연결 안에서 다수의 요청과 응답이 동시에, 독립적으로, 병렬적으로 처리되도록 설계되었습니다.

HTTP/2의 프레임 조립(reassembly)은 HTTP 애플리케이션 계층에서 직접 수행합니다. 즉, TCP로부터 수신된 프레임 데이터를 HTTP/2 프로토콜이 해석하고, 같은 스트림 ID를 가진 프레임들을 모아서 하나의 요청/응답 메시지로 재조립합니다.


✅ 요약 정답

HTTP/2 프레임의 분해/조립은 TCP가 아니라 HTTP 단(애플리케이션 계층)에서 수행됩니다.


🔍 흐름 구조로 다시 보기

less복사편집[네트워크 계층] : IP Packet 수신

[전송 계층] : TCP Segment 수신 (스트림 단위 모름)

[애플리케이션 계층]
→ HTTP/2 Layer가 각 프레임을 파싱
→ Stream ID로 프레임 분류
→ 헤더 프레임 + 데이터 프레임 조합 → HTTP 요청 or 응답 복원

✅ 예시

서버가 다음과 같이 응답을 나눠 보냈다고 가정:

  • Stream 1:

    • HEADERS 프레임 → status, content-type 등

    • DATA 프레임 1 → HTML 일부

    • DATA 프레임 2 → HTML 나머지

HTTP/2는 이 3개의 프레임을 같은 Stream ID(1)로 묶어서 하나의 응답으로 조립


✅ TCP는 프레임에 관심 없음

TCP는 애초에:

  • 바이트 스트림만 전달

  • HTTP/2 프레임 단위를 모르며,

  • Stream ID, Frame type 등은 전혀 해석하지 않음

→ 즉, TCP는 프레임이 어디서 어디까지인지 모른 채 순서만 보장해주는 관심 없는 운반자


✅ 조립은 누가 하는가?

단위
조립 주체

TCP segment → 바이트 스트림

운영체제 커널(TCP 스택)

HTTP/2 frame → 스트림 재조립

HTTP 라이브러리 (예: 브라우저, nghttp2, gRPC)

HTTP 요청/응답 재구성

HTTP 애플리케이션 계층


✅ 관련 프레임 처리 예 (개념적)

java복사편집// 의사 코드: HTTP/2 수신기
while (inputStream.hasData()) {
    Frame frame = parseHttp2Frame(inputStream);

    switch (frame.streamId) {
        case 1:
            stream1Buffer.add(frame);
            if (frame.endOfStream) {
                HttpResponse res = reconstructHttpResponse(stream1Buffer);
                process(res);
            }
            break;
        ...
    }
}

HTTP 3

  • QUIC라는 UDP를 사용하는 프로토콜 사용, TCP가 해주던 기능이 필요하면 UDP 프로토콜 위에 필요한 부분만 추가로 구현하면 되기 때문에 효율적이다.

HTTP 요청 메서드들

같은 경로에 대한 HTTP 요청이더라도 메서드에 따라 동작이 달라진다. 아니, 달라지도록 개발해야 한다. 앞으로 어떤 메서드를 사용할지 고민하게 되는 상황이 많을 것이다.

행위별로 적절한 HTTP 메서드 연결하기

모질라(Mozila)에서 제공하는 HTTP 요청 메서드 리스트를 보면 여러 가지 HTTP 메서드가 있지만 실제로 많이 사용되는 HTTP 요청 메서드는 다음과 같이 정해져 있다.

  • GET : 특정 자원에 대한 조회를 요청하는 메서드이다.

  • HEAD : GET 메서드에 대한 요청과 동일한 효과를 내지만, 바디를 제외한 헤더 부분만 응답으로 받는 메서드이다.

  • POST : 새로운 자원 생성을 요청하는 메서드이다. 새로운 자원은 요청 바디에 있는 내용을 바탕으로 생성된다.

  • PUT : 기존에 있던 자원을 요청 바디에 있는 내용으로 변경하는 메서드이다.

  • PATCH : PUT 처럼 기존 자원을 변경하지만 해당 자원의 전체를 변경하는 것이 아니라 일부만 변경한다.

  • DELETE 특정 자원을 제거한다.

  • OPTIONS : 해당 경로에서 어떤 HTTP 요청 메서드를 사용할 수 있는지 알려 준다.

안전한 메서드와 멱등성 있는 메서드

안전한 메서드라는 것은 대상이 되는 자원의 상태를 변경하지 않는 메서드라는 의미이다. 즐겨찾기 서비스라면 즐겨찾기의 이름을 변경하거나 즐겨찾기의 URL을 변경하지 않는 메서드를 안전한 메서드라고 할 수 있다. HTTP/1.1 명세 문서를 살펴보면 GET, HEAD, OPTIONS 가 각각 안전한 메서드라고 나와 있다. HEAD와 OPTIONS에는 보통 @RequestMapping을 추가해 줄 필요없이 GET 메서드로 @RequestMapping을 추가하면 WAS가 자동으로 생성해 준다. 결국 GET 메서드만 만들어 주면 되는데, 중요한 점은 GET 메서드 API도 '안전한 메서드'로 만들어야 한다는 것이다.

다음은 멱등성이다. 멱등성이란 '한 번 호출한 것과 여러 번 호출한 것이 같은 자원의 상태를 가지는 것'을 의미한다. POST는 대표적인 멱등성이 없는 메서드이다. 멱등성이 있는 메서드는 대표적으로 GET, PUT, DELETE가 있다. 안전한 메서드 GET은 당연히 멱등성도 있다고 할 수 있다. 호출해도 자원의 상태가 바뀌지 않기 때문이다. PATCH 역시 멱등성이 없는 메서드이다.

  • 생성하기(POST) - 생성하기는 멱등성이 없으므로 POST 메서드가 적절하다.

  • 읽기(GET) - 읽기 연산은 안전해야 하므로 GET 메서드가 적절하다.

  • 수정하기(PUT) - 수정하기는 보통 멱등성이 있다. 동일한 내용으로 요청하면 한 번 수정된 후 동일한 상태를 가지기 때문이다. 맥락상 수정한다는 의미에서 PUT이 적절하기도 하다. 자원의 일부만 수정하는 기능이면서 멱등성이 없다면 PATCH를 고려해 볼 수도 있다.

  • 삭제하기(DELETE) - 삭제하기는 보통 멱등성이 있다. 데이터베이스를 사용하면 자원마다 고유한 ID를 가지게 된다. 삭제하기는 해당 ID를 기준으로 삭제를 요청하기 때문에 한 번 삭제된 후로는 동일하게 자원이 삭제된 상태를 유지하게 된다. 따라서 삭제하기는 멱등성이 있다.

두 가지 규칙 준수!

GET은 반드시 안전한 메서드여야 한다.

PUT , DELETE는 멱등성이 있는 메서드여야 한다.

HTTP 응답 상태 코드

상태 코드 대역
의미

1xx

정보성 상태 코드

요청을 받았으나 무언가 계속되는 상태를 나타낸다.

2xx

성공을 의미하는 상태 코드

요청을 성공적으로 수신/이해/수락했다는 것을 의미한다.

3xx

리다이렉트(Redirect)를 의미하는 상태 코드

요청을 서버에서 처리하지 않고 다른 곳으로 유도한다. 리다이렉트되는 경우 2번의 HTTP 트랜잭션이 발생한다.

4xx

클라이언트 오류에 해당하는 상태 코드

잘못된 구문이 포함되어 있거나 어떤 이유에 의해 수행할 수 없다는 것을 의미한다.

5xx

서버 오류에 해당하는 상태 코드

Last updated