[스프링부트 #1] 서블릿 기반 웹 요청/응답 흐름 완전 정복

버퍼 코드 구현, Content-Type, MIME 정리, 서블릿 기반 웹 요청 및 응답 실습을 진행하였고 그것들을 정리하였습니다.
도경원's avatar
Aug 01, 2025
[스프링부트 #1] 서블릿 기반 웹 요청/응답 흐름 완전 정복
 

1. 버퍼 코드 구현, readLine() 메서드

버퍼를 쓰는 이유

  • HttpServletRequest.getReader() 를 통해 클라이언트의 body 데이터를 읽어올 수 있다.
  • BufferedReader 는 한줄씩 읽기 위해 사용 → readLine 호출로 문자열 한 줄을 가져옴
BufferedReader br = request.getReader(); String data; while ((data = br.readLine()) != null) { System.out.println("read buffer data: " + data); }
POST 방식일 때만 body가 있음
readLine() 한 번 읽으면, 다시는 못 읽음 (스트림 소모됨)

2. request , 그리고 주요 메서드

HttpServletRequest 역할

: 클라이언트가 보낸 요청(Request)에 대한 모든 정보를 담고 있음

자주 쓰는 메서드

메서드
설명
getParameter(String)
form-data 또는 query string에서 키 값 읽기
getReader()
body를 직접 읽을 수 있는 Reader 반환
getRequestURI()
요청 URI 경로 (/hello.do)
getHeader(String)
요청 헤더 값 읽기 (User-Agent, Content-Type 등)
getMethod()
HTTP 메서드 타입 (GET, POST 등)

3. response , 그리고 주요 메서드

HttpServletResponse 역할

: 서버가 클라이언트에게 보내는 응답(Response)을 구성하는 객체

자주 쓰는 메서드

메서드
설명
setContentType(String)
MIME 타입 설정 (text/html, application/json 등)
getWriter()
텍스트 응답을 위한 출력 스트림 (PrintWriter)
getOutputStream()
바이트 스트림 응답용 (예: 이미지, 파일 등)

예시 :

response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("<h1>"); out.println("good"); out.println("</h1>"); out.flush();
text/html: 응답 내용이 HTML이라는 의미
charset=utf-8: UTF-8 문자 인코딩을 사용하겠다는 뜻, 이걸 안 하면 한글 깨짐 가능성 있음
PrintWriter는 문자 기반 스트림 (바이너리 X), 이 스트림을 통해 HTML, 텍스트 등을 클라이언트로 전송함
브라우저 화면에는 굵은 큰 글씨로 "good"이 표시됨
out.flush(): 버퍼에 쌓여 있는 데이터를 강제로 클라이언트로 전송

4. Content-Type, MIME 정리

Content-Type 이란 ?

클라이언트가 보내는 데이터 혹은 서버가 보내는 데이터의 형식을 명시하는 HTTP 헤더

주요 MIME 타입

Content-Type
설명
text/html
HTML 응답
application/json
JSON 형식 응답/요청
application/x-www-form-urlencoded
기본 form submit 시 사용되는 타입 (key=value&key2=value2 형태)
multipart/form-data
파일 업로드 등 바이너리 포함된 폼 전송

5. Body

Body는 언제 있는가 ?

  • GET 요청은 보통 body가 없다.
  • POST, PUT, PATCH 등에선 주로 body에 데이터를 담는다.
  • body는 텍스트든 JSON이든 다 스트림 형태로 들어오므로 request.getReader() 로 읽어야 한다.
{ "username": "doythan", "password": "1234" }

6. 실습 코드 예제

@WebServlet("*.do") // *.do로 끝나는 모든 요청을 이 서블릿이 처리함 public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // GET 요청 시 호출됨 System.out.println("doGet called"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { // POST 요청 시 호출됨 System.out.println("doPost called"); // 요청 본문을 BufferedReader로 읽음 (주로 JSON, form-data 읽을 때) BufferedReader br = request.getReader(); String data; // 본문을 한 줄씩 읽으며 출력 while ((data = br.readLine()) != null) { System.out.println("read buffer data: " + data); } // 요청 URI 출력 (/example.do 등) String uri = request.getRequestURI(); // 브라우저 종류나 디바이스 정보 (User-Agent 헤더) String userAgent = request.getHeader("User-Agent"); // 요청의 Content-Type (예: application/json) String contentType = request.getContentType(); // 요청 메서드(GET, POST 등) String method = request.getMethod(); System.out.println("uri: " + uri); System.out.println("userAgent: " + userAgent); System.out.println("contentType: " + contentType); System.out.printf("method: %s\n", method); // 응답 헤더 설정: HTML 문서, UTF-8 인코딩 response.setContentType("text/html;charset=utf-8"); // 응답 출력 스트림 생성 PrintWriter out = response.getWriter(); out.println("<h1>"); out.println("good"); // 브라우저에 <h1>good</h1> 출력됨 out.println("</h1>"); out.flush(); // 버퍼 비우고 클라이언트에 전송 } }
// BufferedReader br = request.getReader(); // String data; // // while ((data = br.readLine()) != null) { // System.out.println("read buffer data: " + data); // } String username = request.getParameter("username"); System.out.println("username: " + username);
서블릿 요청은 1회용 스트림
request.getReader() → 요청 본문을 문자로 읽는 InputStream, 한 번 읽으면 내부 스트림이 소모됨 (더 이상 못 읽음)
getParameter()도 내부적으로 스트림을 읽어서 파싱
따라서 주석 해제 하면 username에는 null

7. 용어 정리

스트림

  • 데이터의 흐름을 추상화한 것
  • 파일, 네트워크, 키보드 입력 등에서 데이터를 "한 줄"처럼 흐르게 다룸
  • 방향성 있음: InputStream(받기, 데이터 읽기) vs OutputStream(보내기, 데이터 쓰기)
  • 문자 스트림: 텍스트용 (Writer), 바이너리 스트림: 파일/이미지용 (OutputStream)

바이너리 (Binary)

  • 0과 1로 이루어진 데이터
  • 이미지, 동영상, 압축파일 등은 바이너리 형태로 전송
  • 텍스트도 결국 바이너리지만, 사람이 보기 쉽게 인코딩된 것일 뿐

flush()

  • 스트림에 쌓인 데이터(버퍼)를 강제로 밀어내는 것
  • 자바는 출력할 때 바로 안 보내고 버퍼에 잠깐 저장
  • flush()는 이걸 클라이언트나 파일로 즉시 전송
Share article

Gyeongwon's blog