안녕하세요! 프론트엔드 개발자라면 반드시 이해해야 하는 핵심 개념, 바로 네트워크 통신이죠! 지난 시간에 이어 이번에는 HTTP 세션이 어떻게 이루어지는지 하나씩 파헤쳐 보겠습니다.
어려운 용어들이 나올 수 있지만, 제가 실무에서 쓰이는 쉬운 예시와 꿀팁들을 팍팍 섞어서 설명해 드릴 테니 걱정 말고 따라오세요! 자, 그럼 시작합니다!
HTTP와 같은 클라이언트-서버 프로토콜(규약)에서 하나의 세션(Session)은 크게 세 가지 단계(Phase)로 이루어집니다.
💡 강사의 부연 설명!
여기서 '세션'이란 클라이언트(브라우저)와 서버가 서로 인사를 나누고 대화를 시작해서, 대화가 끝날 때까지의 하나의 큰 흐름을 말해요!
HTTP/1.1 버전부터는 이 세 번째 단계가 끝났다고 해서 곧바로 연결(Connection)을 무정하게 끊어버리지 않아요. 클라이언트에게 추가적인 요청을 할 수 있는 권한을 주어 연결을 열어둡니다. 즉, 한 번 연결을 맺어두면 두 번째와 세 번째 단계(요청-응답)를 원하는 만큼 반복해서 수행할 수 있다는 뜻이에요!
💡 강사의 실무 TIP!
초창기 웹(HTTP/1.0)에서는 이미지 하나 받을 때마다 연결을 맺고 끊기를 반복했어요. 엄청 비효율적이었겠죠? 이걸 개선한 기능이 바로 'Keep-Alive'입니다. 프론트엔드 개발을 하실 때 여러 API를 연달아 호출해도 속도가 생각보다 빠른 이유는, 이렇게 연결을 재사용하기 때문이랍니다!
클라이언트-서버 프로토콜에서는 언제나 클라이언트가 먼저 연결을 설정(수립)합니다. HTTP에서 연결을 연다는 것은, 밑바탕에 깔려있는 전송 계층(Transport layer)에서 연결을 시작한다는 의미이며, 오늘날 웹에서는 대부분 이 전송 계층으로 TCP를 사용합니다.
컴퓨터의 HTTP 서버에서 사용하는 TCP의 기본 포트(Port)는 80번입니다. 물론 상황에 따라 8000번이나 8080번 같은 다른 포트 번호를 사용할 수도 있어요. 우리가 가져오고자 하는 페이지의 URL에는 도메인 이름과 포트 번호가 모두 포함되어 있습니다. 다만 포트 번호가 기본값인 80일 경우에는 브라우저가 알아서 생략해서 보여줄 뿐이에요. (더 자세한 내용은 http://eomun.ewha.ac.kr/sub/sub05_01.php?mNum=5&sNum=1&boardid=qna&mode=view&idx=927&goPage=&g_idx=(https://developer.mozilla.org/en-US/docs/Web/URI)를 확인해 보세요!)
💡 강사의 부연 설명!
포트(Port)는 쉽게 말해 '건물의 호수'와 같아요. 도메인(example.com)이 아파트 동이라면, 포트 번호(80)는 그 아파트의 몇 호로 찾아갈지 정해주는 거죠. 참고로 보안이 적용된 HTTPS의 기본 포트는443번입니다. 프론트엔드 개발 서버를 띄울 때localhost:3000이나localhost:8080을 많이 보셨죠? 이게 바로 우리가 3000번, 8080번 포트를 사용하겠다고 지정한 거랍니다!
참고 (Note):
클라이언트-서버 모델의 철칙 중 하나는, 클라이언트의 명시적인 요청이 없으면 서버가 먼저 클라이언트에게 데이터를 보낼 수 없다는 것입니다. 하지만 실시간 알림 같은 기능이 필요하잖아요? 그래서 이를 가능하게 해주는 다양한 웹 API들이 등장했습니다. 대표적으로 Push API, Server-sent events (SSE), 그리고 WebSockets API가 이런 특별한 사용 사례를 지원합니다.
연결이 무사히 맺어졌다면, 이제 사용자 에이전트(User-agent)가 요청을 보낼 차례입니다. (보통 사용자 에이전트는 크롬, 사파리 같은 웹 브라우저를 뜻하지만, 구글 검색 엔진 크롤러 봇 같은 프로그램이 될 수도 있어요).
클라이언트의 요청은 텍스트 형태의 지시어들로 구성되며, 각 줄은 CRLF(캐리지 리턴 \r, 이어서 라인 피드 \n - 쉽게 말해 엔터키를 쳐서 줄 바꿈을 한 것)로 구분됩니다. 이 요청 메시지는 크게 세 가지 블록으로 나뉩니다.
POST 요청 메서드를 사용할 때 부가적인 데이터를 담아서 보내는 블록입니다.MDN 사이트의 메인 페이지(https://developer.mozilla.org/)를 가져오면서, 브라우저가 서버에게 "가능하다면 프랑스어(fr) 페이지로 부탁해!"라고 요청하는 예시를 볼까요?
GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
마지막에 빈 줄(Empty line)이 있는 것을 꼭 주목해 주세요! 이 빈 줄은 헤더 블록과 데이터 블록을 분리하는 역할을 합니다. 위 예시처럼 HTTP 헤더에 데이터의 길이를 나타내는 Content-Length가 없으면 데이터 블록은 텅 비어 있는 것으로 간주됩니다. 즉, 이 빈 줄은 "헤더 끝났음!"을 의미하며, 서버는 이 빈 줄을 받는 순간 곧바로 요청을 처리하기 시작합니다.
이번에는 HTML 폼(Form)의 입력 결과를 서버로 전송(POST)하는 예시입니다:
POST /contact_form.php HTTP/1.1
Host: developer.mozilla.org
Content-Length: 64
Content-Type: application/x-www-form-urlencoded
name=Joe%20User&request=Send%20me%20one%20of%20your%20catalogue
💡 강사의 실무 TIP!
실무에서 프론트엔드 개발자가 API로 데이터를 보낼 때POST메서드를 정말 많이 씁니다. 이때 브라우저의 '네트워크(Network) 탭'을 열어보면, 위의 예시처럼Content-Type(우리가 보내는 데이터의 종류)과 실제데이터(Payload)가 담겨 있는 걸 확인할 수 있어요. 요즘은application/json타입으로 많이 보낸다는 점도 기억해 두세요!
HTTP는 자원(Resource)에 대해 우리가 수행하고 싶은 동작(Action)을 나타내는 여러 가지 요청 메서드(Request methods)를 정의하고 있습니다. 명사형으로 쓸 수도 있지만, 보통은 "HTTP 동사(Verbs)"라고 부릅니다. 가장 흔하게 쓰이는 두 가지 찰떡궁합 메서드는 GET과 POST입니다.
GET 메서드: 지정된 자원(데이터)을 달라고 요청합니다. GET 요청은 오직 데이터를 가져오는(Retrieve) 용도로만 사용해야 합니다! (데이터를 수정하거나 삭제하는 데 쓰면 절대 안 됩니다.)POST 메서드: 서버로 데이터를 보내서 서버의 상태를 변경하도록 합니다. HTML 폼(Forms)에서 데이터를 제출할 때 아주 자주 쓰이는 메서드죠.💡 강사의 부연 설명!
이 외에도 데이터를 통째로 수정하는PUT, 데이터의 일부만 수정하는PATCH, 데이터를 삭제하는DELETE등의 메서드도 있어요. 나중에 여러분이 백엔드 개발자와 REST API를 연동할 때 이 동사들을 아주 적절하게 골라서 쓰셔야 한답니다!
클라이언트의 요청이 무사히 도착하면, 웹 서버는 요청을 열심히 처리한 뒤 최종적으로 응답(Response)을 돌려보냅니다. 서버 응답 역시 클라이언트 요청과 쌍둥이처럼 비슷하게 CRLF(줄 바꿈)로 구분된 텍스트 지시어들로 이루어져 있으며, 세 가지 블록으로 나뉩니다.
성공적으로 웹 페이지를 가져왔을 때의 응답 예시입니다:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 55743
Connection: keep-alive
Cache-Control: s-maxage=300, public, max-age=0
Content-Language: en-US
Date: Thu, 06 Dec 2018 17:37:18 GMT
ETag: "2e77ad1dc6ab0b53a2996dfd4653c1c3"
Server: meinheld/0.6.1
Strict-Transport-Security: max-age=63072000
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Vary: Accept-Encoding,Cookie
Age: 7
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>A basic webpage</title>
</head>
<body>
<h1>Basic HTML webpage</h1>
<p>Hello, world!</p>
</body>
</html>
요청한 자원(Resource)이 다른 주소로 영구적으로 이사 갔을 때(이동했음을 알림)의 응답 예시입니다:
HTTP/1.1 301 Moved Permanently
Server: Apache/2.4.37 (Red Hat)
Content-Type: text/html; charset=utf-8
Date: Thu, 06 Dec 2018 17:33:08 GMT
Location: [https://developer.mozilla.org/](https://developer.mozilla.org/) (이곳이 새로운 주소입니다. 브라우저는 이 주소로 다시 자동으로 요청을 보냅니다.)
Keep-Alive: timeout=15, max=98
Accept-Ranges: bytes
Via: Moz-Cache-zlb05
Connection: Keep-Alive
Content-Length: 325 (이 본문에는 브라우저가 자동으로 새 주소로 넘어가지 못할 경우를 대비해 보여줄 기본 안내 페이지가 들어있습니다.)
<!doctype html>… (사용자가 길을 잃지 않도록 돕는 사이트 맞춤형 페이지 내용)
요청한 자원이 존재하지 않을 때(에러 발생)의 응답 예시입니다:
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Content-Length: 38217
Connection: keep-alive
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Content-Language: en-US
Date: Thu, 06 Dec 2018 17:35:13 GMT
Expires: Thu, 06 Dec 2018 17:35:13 GMT
Server: meinheld/0.6.1
Strict-Transport-Security: max-age=63072000
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Vary: Accept-Encoding,Cookie
X-Cache: Error from cloudfront
<!doctype html>… (찾으시는 페이지가 없다는 걸 안내하는 사이트 맞춤형 404 에러 페이지 내용)
HTTP 응답 상태 코드(HTTP response status codes)는 특정 HTTP 요청이 성공적으로 완료되었는지를 명확하게 알려주는 숫자입니다. 응답 코드는 크게 다섯 가지 클래스(그룹)로 나뉩니다: 정보성 응답(1xx), 성공적인 응답(2xx), 리다이렉트(3xx), 클라이언트 에러(4xx), 그리고 서버 에러(5xx)입니다.
200: OK. 요청이 성공적으로 처리되었습니다. (개발자가 가장 좋아하는 코드죠!)301: Moved Permanently. 요청한 자원의 URI(주소)가 변경되었음을 의미합니다. 새로운 주소는 보통 응답의 Location 헤더에 담겨 옵니다.404: Not Found. 서버가 요청받은 자원을 찾을 수 없다는 뜻입니다. (인터넷 서핑하다 가장 많이 보는 반가운(?) 에러죠.)💡 강사의 실무 TIP!
상태 코드는 원활한 프론트엔드-백엔드 협업의 핵심입니다! 숫자 앞자리를 꼭 기억하세요.
- 200번대: 성공! 만세!
- 400번대: 프론트엔드(클라이언트)가 잘못 요청함. (오타가 있거나, 권한이 없거나, 없는 주소를 쳤거나)
- 500번대: 백엔드(서버)가 터짐. (이럴 땐 당당하게 백엔드 개발자분께 문의하세요!)
관련된 내용들을 더 깊이 파고 싶으시다면 아래 링크들을 참고해 보세요! (원본 MDN 문서 링크입니다.)
이 페이지는 MDN 기여자들에 의해 2026년 1월 19일에 마지막으로 수정되었습니다.