클라이언트와 서버

src/content/documents/dev-tools/web-client-server-request-response.json

한 줄 정의

클라이언트는 필요한 일을 요청하는 프로그램이고, 서버는 그 요청을 처리해 결과를 돌려주는 프로그램이다. 웹에서는 둘이 주로 HTTP 요청(Request)과 HTTP 응답(Response)이라는 정해진 형식의 메시지를 주고받는다.

게임서버

클라이언트와 서버는 기계 이름이 아니라 역할이다

스마트폰의 게임 앱이나 PC의 게임 런처는 서버에 일을 부탁하므로 클라이언트 역할을 한다. 서버는 로그인 정보가 맞는지 확인하고, 저장된 캐릭터 정보를 찾아 응답한다. 여기서 중요한 점은 클라이언트와 서버가 특정 종류의 컴퓨터를 뜻하는 것이 아니라 한 번의 통신에서 누가 요청하고 누가 응답하는지를 나타내는 역할이라는 것이다.

게임 앱이 캐릭터를 직접 보관한다고 생각하기 쉽지만, 온라인 게임의 중요한 원본 데이터는 보통 서버가 관리한다. 그래야 다른 기기로 접속해도 같은 캐릭터를 불러오고, 클라이언트에서 수치를 마음대로 바꾸는 일을 줄일 수 있다.

HTTP란?

HTTP(Hypertext Transfer Protocol)는 클라이언트와 서버가 메시지를 어떻게 표현하고 해석할지 정한 응용 계층 프로토콜이다. 쉽게 말해 서로 다른 프로그램도 알아들을 수 있게 만든 대화 규칙이다. 웹 페이지뿐 아니라 게임의 로그인 API나 캐릭터 API도 HTTP를 사용할 수 있다.

브라우저나 게임 앱은 보통 HTTP 메시지를 직접 한 줄씩 만들지 않는다. 프로그램이 제공하는 API를 사용하면 브라우저·운영체제·라이브러리가 알맞은 메시지로 바꾸어 전송한다. 다만 메시지의 구성 요소를 알면 오류를 훨씬 쉽게 찾을 수 있다.

요청은 무엇을 어떻게 해 달라는 메시지다

메서드(method)는 원하는 행동, 경로(path)는 대상을 가리킨다. 헤더(headers)에는 데이터 형식이나 로그인 증표 같은 부가 정보를 넣고, 본문(body)에는 서버로 보낼 실제 데이터를 넣을 수 있다.

POST /api/login HTTP/1.1
Host: game.example
Content-Type: application/json

{
  "username": "new-player",
  "password": "example-only"
}

이 예시에서 POST는 로그인 정보를 서버에 보내 처리해 달라는 의도를 나타내고, /api/login은 대상 경로다. Content-Type 헤더는 본문이 JSON 형식임을 알려 준다. 빈 줄 아래가 본문이다. 비밀번호는 설명을 위한 가짜 값이며, 실제 서비스에서는 반드시 HTTPS를 사용해야 한다.

GET과 POST를 먼저 구분하자

GET은 서버에서 표현을 가져올 때 사용한다. 로그인 뒤 내 캐릭터를 조회한다면 GET /api/characters/me처럼 요청할 수 있다. POST는 서버에 데이터를 보내 처리를 요청할 때 자주 사용한다. 로그인 예시가 이에 해당한다. 실제 API 경로와 메서드는 서비스 설계에 따라 달라진다.

GET /api/characters/me HTTP/1.1
Host: game.example
Authorization: Bearer example-token
Accept: application/json

GET이면 안전하고 POST이면 안전하지 않다는 뜻은 아니다. 민감한 값은 메서드와 관계없이 URL에 넣지 말고, HTTPS와 올바른 인증·권한 검사를 함께 사용해야 한다.

응답은 처리 결과를 알려 주는 메시지다

응답에는 처리 결과를 숫자로 나타낸 상태 코드(status code), 응답에 관한 부가 정보인 헤더, 화면에 사용할 실제 결과인 본문이 들어갈 수 있다.

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 42,
  "name": "라임기사",
  "level": 7
}

대표적으로 200은 요청이 성공적으로 처리되었다는 뜻이다. 400은 요청이 잘못되었음을, 401은 인증 정보가 없거나 유효하지 않음을, 404는 요청한 리소스를 찾지 못했음을, 500은 서버가 예상하지 못한 문제를 만났음을 나타낸다. 상태 코드만으로 모든 원인을 알 수는 없으므로, 개발할 때는 응답 본문과 서버 기록도 함께 확인한다.

HTTP는 상태가 없다는 말

HTTP가 상태가 없다(stateless)는 말은 각 요청의 의미를 다른 요청과 분리해서 이해할 수 있다는 뜻이다. 서버는 같은 연결에서 바로 전에 로그인 요청이 왔다는 이유만으로 다음 캐릭터 조회 요청도 같은 플레이어의 것이라고 가정하면 안 된다.

그래서 로그인에 성공하면 서버가 세션을 식별하는 쿠키를 보내거나 토큰을 발급하고, 클라이언트는 이후 요청에 그 증표를 함께 보낸다. 서버는 증표를 확인해 어느 플레이어인지 판단한다. 쿠키와 토큰의 보관·만료·도난 방지는 별도의 보안 주제이므로 여기서는 매 요청마다 로그인 맥락을 알려 줄 단서가 필요하다는 점만 기억하자.

HTTPS는 HTTP 통신을 TLS로 보호한다

HTTPS는 HTTP를 TLS(Transport Layer Security)로 보호해 전송하는 방식이다. URL이 https://로 시작하고 브라우저가 인증서를 정상적으로 확인했다면, TLS는 통신 중인 데이터를 암호화하고, 전송 도중 몰래 바뀌었는지 검출하며, 일반적인 웹 통신에서는 서버가 해당 도메인의 주체임을 인증한다.

HTTP  : 내용이 평문으로 노출되거나 전송 중 바뀔 위험이 있다.
HTTPS : TLS가 기밀성(암호화)·무결성·서버 인증을 제공한다.

HTTPS 자물쇠가 사이트의 선의를 보증하지는 않는다. 공격자도 자기 피싱 도메인에 정상 인증서를 발급받아 HTTPS를 사용할 수 있다. HTTPS는 현재 접속한 도메인과의 통신을 보호하므로, 로그인 전에는 주소의 철자와 운영 주체도 확인해야 한다.

개발자도구 Network에서 직접 관찰하기

브라우저에서 공개 웹사이트 하나를 열고 다음 순서로 요청과 응답을 확인해 보자. 비밀번호나 개인정보가 필요한 사이트 대신 연습용 공개 페이지를 사용한다.

  1. 브라우저의 개발자도구를 열고 Network 탭을 선택한다.

  2. 기록을 지운 뒤 페이지를 새로고침한다. 문서·이미지·스크립트마다 요청이 따로 생기는지 본다.

  3. 요청 하나를 선택해 Headers에서 Request Method, 요청 URL 또는 경로, Request Headers를 찾는다.

  4. 같은 화면의 Status Code와 Response Headers를 확인하고, Preview 또는 Response에서 응답 본문을 살펴본다.

  5. 주소가 HTTPS인지, 요청 메서드와 상태 코드가 무엇인지 한 문장으로 설명해 본다.

Network 화면에는 쿠키·토큰·폼 데이터 같은 민감한 값이 보일 수 있다. 화면 캡처나 HAR 파일을 다른 사람에게 전달하기 전 반드시 내용을 확인하고 가린다.

전체 흐름 다시 보기

1. 클라이언트가 POST /api/login으로 로그인 정보를 보낸다.
2. 서버가 확인한 뒤 로그인 증표를 응답한다.
3. 클라이언트가 증표와 함께 GET /api/characters/me를 요청한다.
4. 서버가 증표를 확인하고 캐릭터 JSON을 응답한다.
5. 클라이언트가 JSON을 읽어 캐릭터 선택 화면을 그린다.
6. 이 모든 통신은 HTTPS로 보호한다.

관련 문서

인터넷과 웹은 어떻게 동작할까?에서 요청이 서버까지 찾아가는 큰 그림을, Web Server와 WAS의 차이에서 서버 내부의 정적·동적 처리 분담을 이어서 살펴볼 수 있다.

참고 자료

댓글 0

댓글을 불러오는 중…