HTTP 0.9에서 1.0으로의 발전

standardChan·2025년 9월 21일

리얼월드 HTTP

리얼월드 HTTP 를 학습하고 정리한 글입니다.

HTTP 1.0 Syntax

초창기 HTTP의 발전 과정에서 중요한 것은 다음 4가지이다.

  • 메서드와 경로
  • 헤더
  • 바디
  • status code

HTTP 0.9 -> 1.0 -> 1.1 의 과정은 위의 차이에서 기인하니, 이를 중심으로 발전을 이해해보자.

1. 초기 HTTP

1.1 HTTP 의 시작

유럽입자 물리학 연구소 (CERN)의 팀 버너스리가 최초의 웹 서버를 구현(1990)하였다.

이를 바탕으로 발전 시킨 것이 HTTP/0.9 이다.

1.2. HTTP/0.9

HTTP/0.9의 목적

  • “브라우저가 문서를 요청하면, 서버가 그에 맞는 문서를 반환”
  • 그래서 추가적인 정보 없이, 데이터 그 자체만을 전달

HTTP/0.9 구조

  • 요청 : header 없이, URL만을 이용하여 GET 요청을 보낸다.
  • 응답 : header 없이, 문서 데이터만 반환해준다.
  • 검색 기능 또한 제공하였는데, 이때에는 BODY가 없었으므로, URL에 Param으로 필요한 데이터를 같이 전달하는 방식으로 하였다.

한계

  • 하나의 문서만 응답으로 전달 가능하다
  • 모든 문서를 HTML로 취급하여, 이미지 등의 파일 정보를 서버에서 전달하기 어렵다
  • 클라이언트 측에서 검색 이외의 정보 요청이 불가능하다
  • 서버의 응답이 성공/실패 하였는지 확인 할 수 없었다.

2. HTTP/1.0

2.1 HTTP/1.0

HTTP/1.0 에서는 HTTP/0.9와 달리 새롭게 추가된 것들이 있습니다.

curl HTTP1.0

여러 헤더들 (Host, User-Agent, Accept) 들이 추가된 것이 보입니다.

  • > 는 클라이언트 → 서버 전달하는 요청
  • < 는 서버→클라이언트 로 전달받는 응답

> 를 보게되면 다음이 추가된 것을 볼 수 있습니다.

  • GET / HTTP/1.0
  • Host
  • User-Agent
  • Accept
  • Content-Type
  • Date

이들을 헤더 라고 하는데, 이를 중심으로 큰 차이를 먼저 확인하겠습니다.

서버 JS 코드 (실행 시 참고)
    // echo-server.js
    const http = require("http");
    
    const PORT = 3000;
    
    const server = http.createServer((req, res) => {
      let body = [];
    
      req.on("data", (chunk) => {
        body.push(chunk);
      });
    
      req.on("end", () => {
        body = Buffer.concat(body).toString();
    
        // 요청 전체 dump 비슷하게 출력
        console.log("===== Request Dump =====");
        console.log(`${req.method} ${req.url} HTTP/${req.httpVersion}`);
        for (const [key, value] of Object.entries(req.headers)) {
          console.log(`${key}: ${value}`);
        }
        console.log(""); // 헤더 끝
        console.log(body); // body 출력
        console.log("========================");
    
        // 응답: hello! html
        res.writeHead(200, { "Content-Type": "text/html" });
        res.end("<html><body>hello!</body></html>\n");
      });
    
      req.on("error", (err) => {
        console.error("Request Error:", err);
        res.writeHead(500, { "Content-Type": "text/plain" });
        res.end("Internal Server Error");
      });
    });
    server.listen(PORT, () => {
      console.log(`✅ Echo server running at http://localhost:${PORT}`);
    });

2.2 HTTP/1.0 헤더

헤더

위의 이미지의 >, < 로 출력되어있는 라인들이 Body외의 HTTP에서 추가적으로 전달되는 정보입니다.

HTTP/0.9 에서 어떤 파일을 전송하는지, 목적지가 어디인지 등을 같이 전달하기 위해서 헤더를 추가하였는데요,
자주 사용되는 헤더에 대해 알아보겠습니다.

요청 헤더 (client → server)

  • User-Agent : 클라이언트가 자신의 App 이름을 넣는 곳
  • Referer : 서버에서 참고하는 추가 정보 (클라이언트가 요청을 보낸 page url)
  • Authorization : 인증 정보

응답 헤더 (server → client)

  • Content-Type : 파일 종류 지정 (MIME 문자열로 전달)
  • Content-Length : Body 크기 지정 (압축된 경우 압축 후의 길이)
  • Content-Encoding : 압축 형식
  • Date : 문서 날짜
  • X- 로 시작하는 헤더 : 사용자가 자유롭게 붙여서 사용할 수 있는 헤더

2.3 Content-Type과 보안

Content-Type은 브라우저에서 받은 파일을 렌더링할때 중요한 역할을 합니다. 만약에 image인데, test/plain으로 전달을 해버리면 브라우저는 text라고 판단하여, 이미지를 text로 변환한 값을 화면에 그립니다.

저희가 예전에 사용하던 인터넷 익스플로러는 조금 특이하게도 Content-Type 의 MIME 타입을 확인하지 않았습니다. 위와 같은 문제가 발생할 수도 있다고 생각하여 전달되는 내용을 보고 파일 형식을 추측했어요. 이를 Content sniffing 이라고 합니다.

하지만 위 방식의 단점은 직접 파일을 추측해야한다는 것과 이 과정에서 잘못된 추측이 발생할 수 있다는 것이었습니다. text/plain 의 HTML + js 인데, 이를 멋대로 해석해서 HTML/JS 로 판단하는 예시가 있겠네요.

2.4 전자메일 - header, Body

Header, Body의 시초

HTTP/1.0 이전에 전자메일을 네트워크 상으로 전달하곤 했었습니다. 전자메일은 수신자와 같은 관련 정보와 메일 내용을 담는 body로 구성되어 전달되어있었습니다. 이에 착안하여 HTTP에 전자메일과 비슷한 HeaderBody를 추가하게 되었습니다.

// 전자메일
From: alice@example.com
To: bob@example.com
Subject: Meeting Tomorrow
Date: Sun, 21 Sep 2025 10:00:00 +0900
Content-Type: text/plain; charset="utf-8"

Hi Bob,
Let's meet tomorrow at 2 PM.
Thanks,
Alice
// HTTP 요청
POST /login HTTP/1.0
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

username=seokchan&password=1234

전자메일의 From:, To: 등의 값들을 헤더로 변환하였고, 아래의 개행문자와 함께 분리된 메일 내용을 Body로 변환한 것입니다. 그래서 HTTP와 전자메일의 구조자체는 비슷해요.

다만 2가지 큰 차이가 있습니다.

  • 메서드 + 경로
  • status code

위 2가지 사항을 제외하면 HTTP는 고속으로 전자메일을 왕복시키는 것이라고 표현해도 무방할 정도로 닮아있습다.

2.5 뉴스 그룹 - 메서드, status code

HTTP의 메서드와 상태 코드는 뉴스 그룹 에서 착안해 온 것입니다. 뉴스 그룹의 메서드로는 LIST, HEAD, BODY, POST 등이 사용되었습니다. LIST는 서버에 있는 모든 뉴스 그룹 목록을 가져오는데, HTTP의 GET과 비슷한 역할을 했습니다.

이에 착안하여 HTTP에 수많은 메서드가 제안되었고, 다음 세 가지가 POST, GET, HEAD 가 흔히 사용되는 메서드로 사용됩니다. 이후에 HTTP 1.1에 가서야 PUT, DELETE 등이 추가로 지원되었습니다.

HTML Form으로 사용하는 <Form>은 POST, GET만 지원합니다.

상태 코드

여기에서 300번대의 상태코드가 조금 특이한데, 300번대는 서버가 브라우저에게 리다이렉트하도록 지시하는 status 코드를 의미한다.

2.6 URL

URL vs URI

URL과 URI는 URI가 URL을 포함하는 관계로 조금 다릅니다. URI = URL+URN(명명 규칙) 인데, 웹에서는 URN을 잘 안써서 URL과 URI가 비슷한 의미를 갖는다고 합니다.

URL 구조는 다음과 같습니다.

스키마://호스트명/경로

조금더 구체적으로는 아래와 같다.

스키마://사용자:패스워드@호스트명:포트/경로#fragment?Query
https://jeong:1234@localhost:8080/books#fragment?query=1

각각의 기능을 아래와 같아요.

  • 스키마
    http, https, file 등으로 브라우저가 이 스키마를 해석하여 적절한 접속 방법을 선택합니다.
    저희가 Chrome으로 로컬의 pdf를 열면 file:// 경로로 뜨는데요, 이는 크롬이 스키마를 읽고 file 방식으로 해당 파일에 접속했기 때문입니다.

  • 호스트명
    통신 대상이 되는 서버 주소를 의미합니다. 포트가 생략되면 스키마별 기본 포트를 사용해요.

  • 사용자, 패스워드 : 보안 문제 때문에 웹에서는 해당 방식으로 사용하지 않음

  • 프레드먼트 : 앵커 저장

2.7 Body

HTTP/0.9 에서는 요청 시에, 서버로 데이터를 전달하기 어려웠다. 전달하는 유일한 방법은 URL에 Query를 실어서 전달하는 방법 뿐이었기에 파일을 전달할 수 없었습다.

HTTP/1.0에서는 Body에 데이터를 넣어서 전달할 수 있다. 헤더 끝에 빈 줄을 넣으면 그 아래부터는 Body로 인식한다.

헤더1: 헤더 값1
헤더2: 헤더 값2
Content_Length: 바디의 길이

지정된 바이트 수많큼의 바디 데이터

curl로 body를 같이 서버에 전송하고 싶으면 -d 를 사용하면 된다.

$ curl -d "{\"name\":\"Jeong\"} -H "Content-Type: application/json"
  http://localhost:8080

2.8 GET에 Body 실어서 요청하기

사실 GET 요청 시에도 Body에 값을 넣어서 전달할 수 있습니다. 전달하는 데이터 헤더 끝에 빈줄을 넣고 Body를 실어서 전달하면 GET 요청에도 Body를 전달할 수 있습니다.

GET /search?q=hello HTTP/1.0
Host: www.example.com
Content-Type: application/json
Content-Length: 27

{
  "filter": "recent",
  "limit": 10
}

하지만 RFC 7231(HTTP/1.1) (HTTP 사용 지침)에 따르면 이 방식은 추천하지 않고, 서버에 따라서 GET 요청인 경우 Body를 무시하는 경우도 있으니 자제하라고 합니다.

여기에서 말하고 싶은 것은 어떤 HTTP 요청이라도 body 메세지를 추가해서 전달할 수 있다는 것입니다. HTTP 메서드에 따라서 형식이 달라지는 것은 아니라는 것입니다.

profile
호기심 많은 개발자

1개의 댓글

comment-user-thumbnail
2025년 9월 22일

아 나도 책 읽어야 되는데

답글 달기