Contents
1. HTTP는 객체가 아니다2. HTTP 요청(Request)1️⃣ HTTP 요청(Request)의 구조2️⃣ GET 요청3️⃣ URL에 있는 “자원”은 파일이 아니다4️⃣ 버퍼(Buffer)의 필요성5️⃣ POST 요청3. JSON을 보내면 왜 Content-Type이 중요할까?4. 근데 이걸 우리가 직접 다 해야 한다면?5. 그래서 request / response 객체가 생겼다1️⃣ 톰캣 같은 서블릿 컨테이너의 역할2️⃣ HttpServletRequest란?3️⃣ HttpServletResponse란?4️⃣ 필기5️⃣ 실습1. HTTP는 객체가 아니다
1) 네트워크에 객체는 존재하지 않는다
HttpServletRequest request
➡️ 이런 객체는 네트워크에 존재하지 않는다.
2) 실제 네트워크에서는 문자열만 주고 받는다
- 브라우저 ↔ 서버
- 문자(바이트)만 왔다 갔다 한다
즉,
네트워크에는❌ request 객체❌ response 객체⭕ 문자열 덩어리만 있다
3) HTTP는 프로토콜
HTTP는 “이 문자열을 이런 규칙으로 해석하자”라는 약속(프로토콜)
2. HTTP 요청(Request)
브라우저가 서버에게 보내는 HTTP 요청은 항상 정해진 순서의 문자열
1️⃣ HTTP 요청(Request)의 구조
1) HTTP 요청의 기본 모양
요청 첫 줄 헤더들 빈 줄 본문 (있을 수도, 없을 수도)
- Request Line → 무엇을 할지
- Headers → 부가 정보
- 빈 줄 → 여기부터 Body
- Body → 실제 데이터
2️⃣ GET 요청
1) GET 요청이란?
👉 “데이터 좀 줘”
- 조회용
- Body를 안 쓴다
- 정보는 주소(URL) 에 담는다
2) 브라우저 주소창
/hello?name=kim&age=20
➡️ hello라는 자원에서 name은 kim이고 age는 20인 데이터를 요청한다
3) 쿼리스트링
?name=kim&age=20👉 조건
DB로 비유하면
SELECT*FROM hello
WHERE name='kim'AND age=20;즉,
- GET 요청은
- 조건을 URL에 적는 방식
4) 실제 GET 요청
① 브라우저가 서버로 보내는 진짜 모습
GET /hello?name=kim&age=20 HTTP/1.1
Host: localhost:8080
User-Agent: Chrome
Accept: text/html중요한 점
- 이건 객체가 아님
- 그냥 문자열
- 이 문자열이 버퍼에 저장됨
② 예시

cf) body요청(값을 넣어야하는것)
로그인, 로그아웃


x폼타입? 제이슨 아님
파싱해서 본 모습

3️⃣ URL에 있는 “자원”은 파일이 아니다
1) 자원(Resource)
/hello
⬇️
- hello.html 파일 ❌
- hello.java 파일 ❌
대신:
서버가 제공하는 어떤 “대상” 또는 “기능” ➡️ 자원(Resource)
2) 예시
/product/1➡️ 의미 : product 중에서 id가 1인 것
⬇️ DB
SELECT * FROM product WHERE id = 1;3) 자원(Resource)과 식별자 (Identifier)
① 자원(Resource)
서버가 제공하는 대상(데이터, 개념) 을 의미
② 식별자 (Identifier)
- “구분하기 위한 주소” 라는 넓은 개념
- 어떤 자원이나 기능을 식별하기 위한 값
- 자원명 + 추가 경로까지 포함해서 쓰이는 경우가 많음
자원명 ⊂ 식별자

4️⃣ 버퍼(Buffer)의 필요성
서버는 요청을 한 글자씩 받지 않는다.
1) 실제 흐름
- 네트워크로 바이트 도착
- 메모리 공간에 임시 저장
- 그 공간이 버퍼
👉 버퍼 = 임시 문자열 보관함
2) GET 요청의 버퍼
- 요청 줄 + 헤더까지만 버퍼에 있음
- Body 없음
5️⃣ POST 요청
1) POST의 목적
POST의 목적 :insert(삽입)
- 로그인
- 회원가입
- 글 작성
👉 데이터를 서버에 보내야 할 때 사용
2) POST 요청의 실제 모습
POST /login HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
username=kim&password=1234여기서 중요한 포인트 👇
📌 POST의 생성/등록/전송데이터는 body로 전달
📌 빈 줄 : 헤더와 바디를 나누는 경계선
📌 Content-Type : Body를 어떻게 해석할지 알려줌
3. JSON을 보내면 왜 Content-Type이 중요할까?
Content-Type: application/json이게 있으면 서버는
아, 이 Body는 key-value 문자열이 아니라 JSON이구나
라고 판단
➡️ 그래서 프론트는
- 그냥 form이나 fetch를 쓰고
- 서버는 Content-Type 기준으로 처리
4. 근데 이걸 우리가 직접 다 해야 한다면?
매 요청마다 우리가 해야 할 일:
- 첫 줄 나누기
- 메서드 찾기
- 경로 파싱
- 쿼리스트링 분해
- 헤더 Map 만들기
- Content-Length만큼 Body 읽기
- JSON인지 form인지 판단
😱 너무 복잡하고 실수 투성이
5. 그래서 request / response 객체가 생겼다
1️⃣ 톰캣 같은 서블릿 컨테이너의 역할
- HTTP 문자열을 받는다
- 버퍼에 저장한다
- 파싱한다
- 쓰기 쉬운 객체로 바꿔준다
2️⃣ HttpServletRequest란?
👉 “요청 문자열 번역기”
getMethod()→ "GET"
getRequestURI()→ "/hello"
getParameter("name")→ "kim"
3️⃣ HttpServletResponse란?
👉 “응답 문자열 생성기”
- 상태 코드 설정
- 헤더 설정
- Body 쓰기
➡️ 내부에서는 다시 HTTP 응답 문자열을 만들어서
➡️ 버퍼에 넣고
➡️ 네트워크로 보낸다
4️⃣ 필기

5️⃣ 실습
1) 복잡한 코드
public class App {
public static void main(String[] args) throws Exception {
// 1. 소켓서버
// 2. 연결이 되면, stream에 BufferedReader
// 3. 파싱
String buffer = """
GET /hello.do?name=kim&age=20 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0
Accept:text/html
Connection: keep-alive
""";
MyHttpParser request = new MyHttpParser(buffer);
System.out.println(request.getMethod());
MyServlet servlet = new MyServlet();
if (request.getMethod().equals("GET")) {
servlet.doGet(request);
} else {
servlet.doPost(request);
}
}
}import java.util.HashMap;
import java.util.Map;
public class MyHttpParser {
private String method;
private String path;
private String protocol;
private Map<String, String> headers;
public MyHttpParser(String httpRequest) {
parse(httpRequest);
}
private void parse(String httpRequest) {
headers = new HashMap<>();
String[] lines = httpRequest.trim().split("\n");
if (lines.length == 0) {
return;
}
// 첫 번째 줄 파싱: 메서드, 경로, 프로토콜
String[] requestLine = lines[0].trim().split("\\s+");
if (requestLine.length >= 3) {
this.method = requestLine[0];
this.path = requestLine[1];
this.protocol = requestLine[2];
}
// 나머지 줄 파싱: 헤더들
for (int i = 1; i < lines.length; i++) {
String line = lines[i].trim();
if (line.isEmpty()) {
continue;
}
int colonIndex = line.indexOf(':');
if (colonIndex > 0) {
String key = line.substring(0, colonIndex).trim();
String value = line.substring(colonIndex + 1).trim();
headers.put(key, value);
}
}
}
public String getMethod() {
return method;
}
public String getPath() {
return path;
}
public String getProtocol() {
return protocol;
}
public Map<String, String> getHeaders() {
return headers;
}
public String getHeader(String key) {
return headers.get(key);
}
}2) Servlet 활용!
public class MyServlet {
public void doGet(MyHttpParser request) {
System.out.println("doGet호출됨");
System.out.println(request.getPath());
}
public void doPost(MyHttpParser request) {
System.out.println("doPost호출됨");
System.out.println(request.getPath());
}
}Share article