3장_ 요구사항 4: 302 status code 적용

2026. 2. 1. 14:11·Book/자바 웹 프로그래밍 Next Step

 

회원가입 POST 처리 후에 index.html 화면으로 돌아가게 만들고 싶었다. 처음에는 `/user/create` 분기에서 그냥 index.html 파일을 읽어서 200으로 내려주는 방식으로 해결했는데, 그 방식은 새로고침 시 POST 재전송 문제가 생길 수 있었다. 그래서 이번에는 302 리다이렉트를 직접 구현해서 “POST 처리 → GET으로 페이지 이동” 흐름으로 바꿨다.

 

 

제일 중요한 규칙 1개

HTTP는 요청 1번 → 응답 1번이 기본 단위다.
서버는 “완료했으니 /index.html로 가”라고 응답 할 수는 있지만, 그 말 자체가 /index.html 요청을 대신 해주진 않는다.

즉 302는 “새 요청을 만들게 하는 응답”이지, “index.html을 담아서 주는 응답”이 아니다.

 

 

내가 헷갈렸던 부분

회원가입 완료한 다음, 서버가 302로 /index.html로 가라고 했는데
그럼 index.html 바이트를 읽어서 보내는 건 어디서 하냐?
302 응답에는 바디가 없다며?

정답은 이거다.

index.html 바이트를 읽어서 보내는 건 `GET /index.html` 요청을 처리하는 코드에서 한다.
302는 거기까지 “도착”시키는 안내문일 뿐이다.

 

 

진짜로 ‘두 번’ 요청이 발생한다 (이게 포인트)

회원가입 완료 후의 네트워크 흐름을 실제로 쓰면 “요청이 두 번”이다.

(A) 1번째 요청: 회원가입 요청

브라우저 → 서버:

POST /user/create HTTP/1.1
... (헤더)
(blank line)
userId=...&password=...&name=...&email=...

서버는 여기서 (지금은 로그만 찍지만) 원래라면 회원 저장 같은 “회원가입 처리”를 한다.

그리고 여기서 응답 방식이 갈린다.

(B-1) 200 OK로 index.html을 “바로 보내는 방식”(이전 방식)

서버 → 브라우저:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: ...
(blank line)
(index.html 내용)

이 방식은 `/user/create`에 대한 응답 바디로 index.html을 직접 실어 보내는 구조이다.
그래서 서버 코드가 `/user/create` 분기 안에서 바로 Files.readAllBytes(Path.of("webapp", "index.html")) 같은 걸 실행하는 형태가 된다.

요청은 1번이고, 응답에서 바로 페이지를 내려준다.

하지만 문제는 “현재 페이지의 정체”가 `/user/create POST` 결과로 남아버린다는 점이다.
그래서 새로고침 시 POST 재전송(폼 재전송 경고) 같은 흐름이 생길 수 있다.

(B-2) 302 리다이렉트 방식(지금 방식)

서버 → 브라우저:

HTTP/1.1 302 Found
Location: /index.html
(blank line)

여기서 끝이 아니다.

브라우저는 `Location`을 보고 자동으로 2번째 요청을 새로 만든다.

브라우저 → 서버 (2번째 요청):

GET /index.html HTTP/1.1
... (헤더)
(blank line)

그리고 서버는 이때 정적 파일 로직에서 index.html을 읽어서 200 OK로 내려준다.

서버 → 브라우저:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: ...
(blank line)
(index.html 내용)

즉, 302가 index.html을 보내는 게 아니다.
302 때문에 브라우저가 GET /index.html을 “다시 요청”하고,
그 요청에 대해 서버가 index.html을 읽어서 보내는 것이다.

 

 

“회원가입 완료한 다음”인데 왜 계속 /user/create가 나오냐

“회원가입 완료한 다음”이라고 말해도, 네트워크 순서는 이렇게 된다.

  • 완료 이전에 `/user/create` 요청이 반드시 한 번은 간다 (가입 처리 자체니까)
  • 완료 직후에 “다음 화면을 어떻게 보여줄지” 선택한다
    • 200으로 바로 HTML 내려주면: 추가 요청 없음
    • 302로 보내면: GET /index.html 추가 요청 발생

“완료한 다음”은 사실 /user/create 처리가 끝난 직후를 의미하고, 그 직후에 200을 줄지 302를 줄지 갈리는 것이다.

 

 

코드

if ("POST".equals(method) && url.startsWith("/user/create")) {
                String requestBody = IOUtils.readData(br, contentLength);
                Map<String, String> params = HttpRequestUtils.parseQueryString(requestBody);
                User user = new User(
                    params.get("userId"),
                    params.get("password"),
                    params.get("name"),
                    params.get("email")
                );
                log.debug("User : {}", user);
                DataOutputStream dos = new DataOutputStream(out);
                response302Header(dos);
            } else {
                DataOutputStream dos = new DataOutputStream(out);
                byte[] body = Files.readAllBytes(Path.of("webapp", url));
                response200Header(dos, body.length);
                responseBody(dos, body);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

`user/create` 처리 후에 `302`로 `Location`만 내려준다.

즉, 이 코드를 실행한다.

private void response302Header(DataOutputStream dos) {
        try {
            dos.writeBytes("HTTP/1.1 302 Found \r\n");
            dos.writeBytes("Location: /index.html\r\n");
            dos.writeBytes("\r\n");
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

 

이 방식으로 얻는 효과

이제 회원가입 이후 브라우저는 최종적으로 GET /index.html 페이지에 위치하게 된다.

그래서:

  • 주소창이 /user/create에 머무르지 않는다.
  • 새로고침이 POST 재전송이 아니라 GET /index.html 새로고침이 된다.
  • “POST 처리 후 다음 화면은 GET으로 보여준다”는 흐름이 만들어진다. (PRG 패턴 방향)

 

 

 


출처 : 《자바 웹 프로그래밍 Next Step》, 박재성, 로드북

'Book > 자바 웹 프로그래밍 Next Step' 카테고리의 다른 글

5장_: 임베디드 톰캣으로 웹 서버 띄우기  (0) 2026.02.05
3장_ 로깅: System.out.println() 대신 로깅을 써야 하는 이유  (0) 2026.02.02
3장_ 요구사항3: POST방식으로 회원가입  (0) 2026.02.01
3장_ 메모: 요청 메시지의 형태  (0) 2026.01.31
3장_ 메모: HTTP 요청 라인 파싱과 멀티 스레드 처리  (0) 2026.01.31
'Book/자바 웹 프로그래밍 Next Step' 카테고리의 다른 글
  • 5장_: 임베디드 톰캣으로 웹 서버 띄우기
  • 3장_ 로깅: System.out.println() 대신 로깅을 써야 하는 이유
  • 3장_ 요구사항3: POST방식으로 회원가입
  • 3장_ 메모: 요청 메시지의 형태
sqaxe1
sqaxe1
woojoo-devlog 님의 블로그 입니다.
  • sqaxe1
    Woojoo's Devlog
    sqaxe1
  • 전체
    오늘
    어제
    • 분류 전체보기 (148)
      • Backend (9)
        • Servlet (7)
        • Spring (2)
      • Frontend (1)
      • CS (0)
      • Book (33)
        • 자바 웹 프로그래밍 Next Step (30)
        • 테스트 주도 개발: 고품질 쾌속개발을 위한 TDD.. (1)
        • 성공과 실패를 결정하는 1%의 네트워크 원리 (2)
      • Engineering (0)
        • Testing (0)
      • Infra (6)
        • AWS (6)
      • Java (4)
      • Network (1)
      • 김영한 (28)
        • 자바 입문 (8)
        • 실전 자바 - 기본편 (6)
        • 실전 자바 - 중급편 (10)
        • 실전 자바 - 고급편 (4)
      • Web (39)
        • Web Basics (39)
      • Project (24)
        • NeoSquare (0)
        • Memo Evolution (24)
      • 정보처리기사 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    aws
    개발서적
    java
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
sqaxe1
3장_ 요구사항 4: 302 status code 적용
상단으로

티스토리툴바