이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.
기초개념 › 네트워크
HTTP 요청
HTTP 요청은 어떻게 생긴 글인가
브라우저가 서버에 보내는 HTTP 요청은 정해진 모양의 글자 몇 줄입니다. 첫 줄(요청 줄)에는 메서드, 경로, 버전을 적습니다. 그 아래에는 "이름: 값" 꼴의 줄인 헤더를 적고, 아무 글자도 없는 빈 줄로 헤더가 끝났음을 알립니다(본문이 없는 요청은 여기서 끝납니다). 서버는 이 글을 읽어 무엇을 달라는 요청인지 압니다. 이 실습은 첫 줄, Host 줄, 마지막 빈 줄을 하나씩 바꾸거나 지워 가며 같은 서버(/hello 주소만 만들어 둔 서버)에 글자를 그대로 보내, 서버가 그 글을 요청으로 읽는지, 어떤 응답을 돌려주는지, 우리가 쓴 서버 코드까지 가는지를 봅니다. 코드 칸의 (빈 줄)은 아무 글자도 없는 줄을 눈에 보이게 적은 것입니다.
실행으로 대조 · Node.js 24.18.0의 http 서버에 열두 가지 조합의 글자를 그대로 보내 대조
이 실습에 나오는 개념
- 요청 줄(request line)
- 요청 줄은 HTTP 요청의 맨 첫 줄로, 메서드, 요청 대상(보통 경로), HTTP 버전을 공백으로 나누어 차례로 적는다. 예를 들어 GET /hello HTTP/1.1은 /hello에 대해 GET(달라는 요청)을 HTTP/1.1 규칙으로 보낸다는 뜻이다. 서버는 이 줄로 무엇을 달라는 요청인지 알아낸다. 세 칸의 모양이 맞지 않으면 서버는 그 글을 요청으로 읽지 못하고, RFC 9112는 잘못된 요청 줄에 400 응답을 돌려주도록 권한다(3.2절).
- Host 헤더
- Host는 요청이 어느 사이트(호스트 이름과 포트)로 온 것인지를 알리는 헤더로, 값은 localhost:8080처럼 적는다. 한 서버가 여러 사이트를 맡을 수 있어서 서버가 어느 사이트의 요청인지 구분하는 데 쓴다. RFC 9112는 클라이언트가 모든 HTTP/1.1 요청에 Host 헤더를 보내야 하고, 서버는 Host가 없는 HTTP/1.1 요청에 400(Bad Request)으로 응답해야 한다고 정한다(3.2절). Node.js의 http 모듈도 Host가 없는 요청을 애플리케이션 코드에 넘기지 않고 400으로 답한다.
- HTTP 요청의 끝(빈 줄)
- HTTP 요청은 요청 줄, 헤더 줄들, 아무 글자도 없는 빈 줄 순서로 쓰며, 빈 줄이 헤더가 끝났다는 표시다(RFC 9112 2.1절). 줄바꿈은 CRLF(캐리지 리턴과 줄 바꿈 두 글자)로 적는다. 서버는 이 빈 줄이 와야 요청이 끝까지 왔다고 보고 처리를 시작하므로, 빈 줄이 오지 않으면 뒤에 글자가 더 오는 줄 알고 기다린다. 본문이 있는 요청에서는 빈 줄 다음부터가 본문이다.
- HTTP 상태 코드
- 서버가 요청을 처리한 결과를 나타내는 세 자리 숫자다. 2xx는 성공, 3xx는 다른 위치로의 이동(리다이렉션), 4xx는 클라이언트의 요청에 문제가 있음, 5xx는 서버 쪽 오류를 뜻한다. 200(성공), 201(생성됨), 400(잘못된 요청), 401(인증 필요), 403(권한 없음), 404(없음), 500(서버 오류)이 자주 쓰인다.
이렇게 바꿔 보세요
- 처음 설정으로 — 모양이 맞고 /hello 경로가 있는 요청. 서버 코드가 200과 본문을 돌려줍니다.
- 경로를 /nothing으로 바꾸면 — 모양은 맞지만 서버에 없는 경로. 서버 코드가 404로 답합니다.
- Host 줄을 지우면 — 요청으로는 읽히지만 Host가 없어 Node.js가 서버 코드에 넘기지 않고 400으로 거절합니다.
- 첫 줄에서 GET과 HTTP/1.1을 지우면 — 요청으로 읽히지 않아 400. 서버 코드까지 가지 못합니다.
- 마지막 빈 줄을 지우면 — 끝을 알리는 줄이 없어 서버가 기다리고, 응답이 오지 않습니다.
처음 설정으로 실행하면
- 브라우저 주소창에 localhost:8080/hello 주소를 입력하면, 브라우저는 서버에 연결해 아래와 같은 글자를 보냅니다. 서버는 /hello 주소만 만들어 둔 서버입니다.
- 서버를 이루는 Node.js가 첫 줄을 읽습니다. 읽은 글은 "GET /hello HTTP/1.1"입니다. 첫 줄(요청 줄)에는 세 가지가 차례로 적힙니다. GET은 메서드로 무엇을 하려는지(달라는 요청), /hello는 경로로 무엇에 대해서인지, HTTP/1.1은 어떤 규칙으로 쓴 글인지입니다. 세 칸이 모두 있어 요청 줄로 읽힙니다.
- Node.js가 다음 줄을 읽습니다. 읽은 글은 "Host: localhost:8080"입니다. "이름: 값" 꼴의 줄을 헤더라고 합니다. Host 헤더는 이 요청이 어느 사이트(주소)로 온 것인지를 알려 줍니다.
- Node.js가 다음 줄을 읽었더니 아무 글자도 없는 빈 줄입니다(화면의 (빈 줄)). 빈 줄은 헤더가 끝났다는 표시여서, Node.js는 요청이 끝까지 왔다고 판단합니다.
- Node.js가 읽은 요청에서 메서드는 GET, 경로는 /hello입니다. 모양이 맞고 Host도 있어서, Node.js가 이 요청을 우리가 쓴 서버 코드에 넘깁니다.
- 우리가 쓴 서버 코드가 경로를 봅니다. /hello는 만들어 둔 주소라서, 200 응답과 본문 "안녕하세요"를 만듭니다. 이 코드는 화면에 보이지 않지만, 경로가 /hello인 GET 요청에만 이렇게 답하게 만들어 두었습니다.
- 브라우저가 200 응답을 받습니다. 본문은 "안녕하세요"입니다.
실행 결과
- HTTP 요청은 브라우저가 서버에 보내는 글자 몇 줄입니다. 첫 줄(요청 줄)에 메서드, 경로, 버전을 적고, 그 아래에 "이름: 값" 꼴의 헤더를 적고, 빈 줄로 끝을 알립니다.
- 서버(Node.js)는 이 글을 첫 줄부터 읽어 GET /hello 요청이라는 것을 알았고, 빈 줄에서 요청이 끝났다고 판단해 우리가 쓴 서버 코드에 넘겼습니다. 서버 코드가 경로를 보고 200으로 답했습니다.
코드
GET /hello HTTP/1.1
Host: localhost:8080
(빈 줄)
이 모형의 전제
서버는 Node.js 24.18.0의 http 모듈로 만든 것 하나로, GET /hello에 200과 본문 "안녕하세요"를, 그 밖의 경로에는 404를 돌려줍니다. 열두 가지 조합을 모두 127.0.0.1의 이 서버에 net 모듈로 글자 그대로 보내(줄 끝은 CRLF), 받은 응답의 상태 줄과 본문, 우리가 쓴 요청 처리 함수가 불렸는지와 그 함수가 받은 method와 url을 확인해 모형과 대조했습니다. 화면의 (빈 줄)은 아무 글자도 없는 줄을 눈에 보이게 적은 것이고, 빈 줄이 없는 조합은 마지막 줄의 줄바꿈까지만 보냈습니다. "응답 없음 (기다림)"은 글자를 보낸 뒤 1.5초 동안 응답이 한 바이트도 오지 않았다는 뜻입니다. Node.js가 언제까지 기다리다 포기하는지는 보지 않았습니다. 모양이 틀린 첫 줄(/hello)은 Node.js가 요청으로 읽지 못해 clientError 오류(HPE_INVALID_METHOD)를 내고 스스로 400을 돌려주며, 이때 뒤의 줄이 어떻든 첫 줄만 보냈을 때도 400이 왔습니다. Host가 없는 요청은 빈 줄이 와서 헤더가 끝난 뒤에, Node.js가 우리 코드를 부르기 전에 스스로 400을 돌려주고(요청 처리 함수는 불리지 않았고 clientError도 나지 않았습니다), Host 검사를 끈 서버(requireHostHeader: false)에 같은 글자를 보내면 처리 함수가 GET 요청을 받았으므로 요청 줄까지는 정상으로 읽힌 것입니다. 이것들은 이 Node.js 버전에서 관찰한 동작입니다. 문서로 확인한 것은 RFC 9112의 2.1절(메시지 형식: 요청 줄과 헤더 뒤의 빈 줄), 3절(요청 줄: 메서드, 요청 대상, 버전 세 칸), 3.2절(HTTP/1.1 요청에 Host가 없으면 서버는 400으로 응답해야 한다)과 RFC 9110의 7.2절(Host), 15.5.1절(400), 15.5.5절(404)입니다. 화면의 요청은 헤더를 Host 하나만 남긴 최소한의 모양이고, 본문이 없는 GET 요청만 다뤘습니다. 400을 돌려주는 방식은 서버마다 다를 수 있으며, 이 화면은 Node.js 서버의 동작입니다. 서버의 코드는 화면에 보이지 않습니다. 같은 주제의 세부 동작(응답의 모양, 상태 코드 전체)은 "세부 동작 실습: HTTP 메시지와 상태 코드"에서 다룹니다.
앞 실습: DNS · 다음 실습: HTTP 메서드