HTTP 요청과 응답이란?

북금곰·2026년 7월 15일

백엔드 기본 지식

목록 보기
4/29

HTTP 요청과 응답은 클라이언트와 서버가 서로 대화하는 기본 형식이며, 백엔드 API는 결국 이 요청을 읽고 적절한 응답을 만드는 코드다.

HTTP 요청과 응답이란?

MDN의 HTTP 개요에서는 HTTP를 웹에서 데이터를 주고받기 위한 프로토콜로 설명한다. 웹 브라우저 같은 클라이언트가 요청을 보내고, 서버가 그 요청에 대한 응답을 돌려주는 구조다.

MDN의 HTTP 메시지 문서에서는 HTTP 메시지를 크게 두 가지로 나눈다.

Request: 클라이언트가 서버로 보내는 메시지
Response: 서버가 클라이언트로 돌려주는 메시지

요청은 보통 다음 요소를 가진다.

HTTP method
요청 경로
HTTP 버전
Headers
Body

응답은 보통 다음 요소를 가진다.

HTTP 버전
Status code
Status message
Headers
Body

즉, HTTP는 단순히 URL을 호출하는 것이 아니라, 정해진 형식의 메시지를 주고받는 방식이다.

HTTP 요청 메시지를 살펴보자

처음에는 HTTP 요청을 이렇게 생각하기 쉽다.

“그냥 API 주소 호출하는 거 아닌가?”

예를 들어 이런 주소를 호출한다고 해보자.

/users/1

하지만 실제 요청에는 주소만 있는 것이 아니다.

GET /users/1 HTTP/1.1
Host: example.com
Accept: application/json

여기에는 여러 정보가 들어 있다.

GET: 어떤 동작을 원하는지
/users/1: 어떤 자원을 대상으로 하는지
HTTP/1.1: 어떤 HTTP 버전 형식인지
Host: 어느 서버에 보내는지
Accept: 어떤 응답 형식을 원하는지

POST 요청이라면 body도 들어갈 수 있다.

POST /users HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "name": "junior",
  "email": "junior@example.com"
}

그래서 HTTP 요청은 “주소 하나”가 아니라, 서버에게 보내는 하나의 편지에 가깝다.

음식 주문에 비유하자면

HTTP 요청과 응답은 음식 주문과 비슷하다.

손님이 주문서를 낸다.

메뉴: 김치찌개
요청 사항: 덜 맵게
수량: 1개

직원은 주문서를 보고 주방에 전달한다. 주방은 음식을 만들고 결과를 돌려준다.

상태: 주문 성공
결과: 김치찌개 1개

HTTP에서는 이렇게 바뀐다.

클라이언트:
GET /menus/kimchi-stew 요청

서버:
200 OK 응답
{
  "name": "김치찌개",
  "price": 9000
}

요청은 “무엇을 해달라”는 메시지고, 응답은 “처리 결과는 이렇다”는 메시지다.

코드로 적용해보기

사용자 정보를 조회하는 API를 생각해보자.

클라이언트는 이런 요청을 보낸다.

GET /users/1 HTTP/1.1
Host: api.example.com
Accept: application/json

Spring Boot에서는 이 요청을 이렇게 받을 수 있다.

@RestController
public class UserController {

    @GetMapping("/users/{id}")
    public UserResponse getUser(@PathVariable Long id) {
        return new UserResponse(id, "junior-backend");
    }
}

서버는 응답을 이렇게 돌려줄 수 있다.

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

{
  "id": 1,
  "name": "junior-backend"
}

이 흐름을 나눠보면 단순하다.

1. 클라이언트가 GET /users/1 요청을 보낸다.
2. 서버는 /users/{id}에 맞는 Controller 메서드를 찾는다.
3. id 값 1을 꺼낸다.
4. 사용자 정보를 만든다.
5. JSON 응답을 돌려준다.

POST 요청도 보자.

POST /users HTTP/1.1
Content-Type: application/json

{
  "name": "junior",
  "email": "junior@example.com"
}

Spring Boot에서는 이렇게 받을 수 있다.

@RestController
public class UserController {

    @PostMapping("/users")
    public UserResponse createUser(@RequestBody UserCreateRequest request) {
        return new UserResponse(1L, request.name(), request.email());
    }
}

여기서 중요한 점은 @RequestBody다. HTTP 요청 body에 들어온 JSON을 Java 객체로 바꿔 받을 때 사용한다.

public record UserCreateRequest(
    String name,
    String email
) {
}

프로젝트할 때 조심할 부분

HTTP 요청과 응답을 다룰 때는 세 가지를 특히 조심해야 한다.

첫째, HTTP 메서드를 아무렇게나 쓰지 않는 것이다.

GET: 조회
POST: 생성 또는 처리 요청
PUT/PATCH: 수정
DELETE: 삭제

물론 실무에서는 예외가 생길 수 있지만, 처음에는 이 기본 의미를 지키는 것이 좋다.

둘째, 상태 코드를 대충 200으로만 보내지 않는 것이다.

200 OK: 요청 성공
201 Created: 생성 성공
400 Bad Request: 잘못된 요청
401 Unauthorized: 인증 필요
403 Forbidden: 권한 없음
404 Not Found: 대상 없음
500 Internal Server Error: 서버 내부 오류

응답 body에 “실패”라고 써놓고 status code는 200으로 보내면, API를 사용하는 쪽에서 실패를 판단하기 어려워진다.

셋째, 요청 body를 그대로 믿지 않는 것이다.

{
  "name": "",
  "email": "not-email"
}

클라이언트가 잘못된 데이터를 보낼 수 있으므로 서버는 반드시 검증해야 한다.

필수 값이 있는가?
형식이 맞는가?
현재 사용자가 이 요청을 해도 되는가?
요청한 자원이 존재하는가?

프론트엔드 검증은 사용자 경험을 위한 것이고, 백엔드 검증은 시스템을 지키기 위한 것이다.

정리

HTTP 요청과 응답은 클라이언트와 서버가 대화하는 기본 형식이다.

요청은 보통 이렇게 구성된다.

Method
Path
Headers
Body

응답은 보통 이렇게 구성된다.

Status code
Headers
Body

백엔드 개발자는 이 요청을 읽고, 적절한 로직을 실행한 뒤, 클라이언트가 이해할 수 있는 응답을 만들어야 한다.

나는 HTTP를 이렇게 이해하고 있다.

HTTP는 브라우저와 서버가 서로 오해하지 않기 위해 사용하는 약속된 대화 방식이다.

이 관점으로 보면 @GetMapping, @PostMapping, @RequestBody, @PathVariable, status code, JSON 응답 같은 것들이 따로 노는 개념이 아니라 하나의 흐름으로 연결된다.

profile
주니어개발자

0개의 댓글