<< 학습 목표 >>

1. 포워딩의 두 가지 방식에 대해서 설명할 수 있다.

2. 세 가지 방식의 포워딩 코드를 작성할 수 있다.

3. 세 가지 방식 포워딩의 특징을 설명할 수 있다.


지금까지는 클라이언트에게 "결괏값" 을 보내거나 "결괏값을 담고 있는 페이지"를 보냈음

경우에 따라서는 클라이언트에게 "결과로 B 페이지로 이동해!" 라고 지시해야하는 경우가 생김

이렇게 "다른 곳으로 이동해!" 라고 지시하는 걸 포워딩(Forwarding) 이라고 함

 

포워딩을 하는 방법은 크게 두 가지가 있음

1. 클라이언트에게 이동할 곳을 지정해주는 방법

2. 서버 안에서 이동하는 방법

 

대출을 하기 위해서 은행에 방문한 상황을 예로 들어보자

대출해야하니 [ 대출 파트 ] 로 가야하지만 [ 예금, 출금, 적금 파트 ] 로 가서 "대출하러 왔는데요~" 라고 한 상황임

은행 = 서버 / 각 파트 직원 = 서블릿 / 고객 = 클라이언트

 

그때 직원이 [ 대출은 대출 파트에 가셔야합니다. ] 라고 했다면 포워딩의 1번 상황임

고객이 직접 [ 대출 파트 ] 로 이동해야하는 것처럼 포워딩 1번 방식을 사용하면 서버는 클라이언트에게 이동(포워드 / Forward) 할 경로를 알려줘야하고 클라이언트는 해당 경로로 이동해야함

( 이 상황은 그저 예인것으로 포워딩도 이와 같은 순서로 동작하지는 않음 / "이런 느낌의 간단한 포워딩이 있구나" 정도로만 생각하면 됨 )

 

마찬가지로 대출해야하니 [ 대출 파트 ] 로 가야하지만 [ 예금, 출금, 적금 파트 ] 로 가서 "대출하러 왔는데요~"(1) 라고 한 상황일 때 직원1이 [ 직원2님~ 고객님 대출하려고 오셨는데 이런이런 저런저런거 확인해주세요 ] 라고 대신 요청(2)을 하고 직원2는 직원1이 요청한 처리(3)를 한 후 결과를 직원1에게 되돌려줌(4) 그리고 나서 직원1이 그 결과를 고객에게 알려주는 것(5)

( 이 상황은 그저 예인것으로 포워딩도 이와 같은 순서로 동작하지는 않음 / "이런 느낌의 복잡한 포워딩이 있구나" 정도로만 생각하면 됨 )

 

개발에서 포워딩을 해야되는 상황이 언제가 있을까?

생각 보다 굉장히 많은 상황에서 포워딩이 필요함

 

네이버에 로그인을 해보자

아이디, 비밀번호를 입력하고 [ 로그인 ] 버튼을 눌러보자

로그인에 성공했을 때 어떻게 되는지?

첫 페이지로 이동(포워딩 / forwarding)이 됨

 

네이버에서 검색을 해보자

검색 결과를 보여주기 위해서 검색 결과 페이지로 이동(포워딩 / forwarding)이 됨

 

이렇게 대부분의 상황에서 포워딩이 필요함


여기서는 포워딩의 첫 번째 방법인

1. 클라이언트에게 이동할 곳을 지정해주는 방법

을 배워보자

 

클라이언트에게 이동할 곳을 지정해주는 방법은 다양하지만 주로 다음과 같은 방법들을 사용함

1. JS의 location.href 를 사용

2. 요청 정보(HttpServletRequest)의 sendRedirect 메서드를 사용

3. 응답 정보(HttpServletResponse)의 addHeader 메서드를 사용

 

로그인 페이지와 서블릿을 사용해서 위 1, 2, 3 포워딩 방법을 배우자


포워딩의 첫 번째 방법(클라이언트에게 이동할 곳을 지정해주는 방법) 중 첫 번째 방법을 알아보자

<< JS의 location.href 를 사용 >>

이 방법의 경우 서버에서 포워딩을 위해 할 것이 없음

클라이언트의 JS에서 location.href 를 사용하면 됨

 

먼저 로그인 서블릿을 만들자

chapter04 -> login1 서블릿을 만들고 아래 코드를 입력하자

서버는 포워딩(이동) 경로를 명시해주지 않았고 아이디와 비밀번호가 tempId, tempPw와 일치하면 200 상태 코드를 응답하고 아이디 또는 비밀번호가 tempId, tempPw와 일치하지 않으면 400 상태 코드를 응답함

package chapter04;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/chapter04/login_1")
public class Login1 extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		
		String tempId = "myId";
		String tempPw = "myPw";
		
		if(id.equals(tempId) && pw.equals(tempPw)) {
			response.setStatus(200);
		} else {
			response.setStatus(400);
		}
	}

}

 

요청하고 요청 결과에 맞게 포워딩 하기 위한 페이지를 만들자

<< 로그인에 성공했을 때 보여줄 페이지 >>

webapp -> chapter04 -> loginSuccess.html 을 추가하고 아래 코드를 입력 하자

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>로그인 성공!</title>
</head>
<body>
	<h1>로그인에 성공하셨습니다!</h1>
</body>
</html>

 

<< 로그인 요청을 보낼 페이지 >>

webapp -> chapter04 -> login1.html 을 추가하고 아래 코드를 입력 하자

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>로그인</title>
</head>
<body>
	<form action="/studyProject/chapter04/login_1" method="POST">
		아이디: <input type="text" name="id"><br>
		비밀번호: <input type="password" name="pw"><br>
		<button type="button">로그인</button>
	</form>
	
	<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
	<script>
		$("button").on("click", function() {
			let id = $("input[name=id]").val();
			let pw = $("input[name=pw]").val();
			
			$.ajax({
				url: $("form").attr("action"),
				type: $("form").attr("method"),
				data: "id="+id+"&pw="+pw,
				success: function() {
					location.href = "/studyProject/chapter04/loginSuccess.html";
				},
				error: function() {
					alert("아이디 또는 비밀번호를 확인해주세요.");
				}
			})
		});
	</script>
</body>
</html>

 

우리가 지금 어떤 포워딩을 배우고 있다? JS의 location.href 를 사용한 포워딩

웹 페이지의 JS 를 사용해서 로그인에 성공했다면 로그인 성공 페이지로 이동하도록 포워딩 하고 있음(1)

 

이제 서버를 시작한 후 login.html에 접속해 아이디를 myId 로, 비밀번호를 myPw 로 입력하고 [ 로그인 ] 버튼을 눌러보자

서버는 200 상태 코드를 응답하고 200 상태 코드를 응답 받은 클라이언트는 success: function 내 코드가 동작해 로그인 성공 페이지로 이동(포워딩)함


포워딩의 첫 번째 방법(클라이언트에게 이동할 곳을 지정해주는 방법) 중 두 번째 방법을 알아보자

<< 요청 정보(HttpServletRequest)의 sendRedirect 메서드를 사용 >>

이 방법은 서버가 클라이언트에게 이동할 경로를 지정해주는 방법임

그래서 클라이언트가 포워딩을 위해 할 일은 없음

 

로그인 서블릿을 추가하자

chapter04 -> login2 서블릿을 만들고 아래 코드를 입력하자

package chapter04;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/chapter04/login_2")
public class Login2 extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		
		String tempId = "myId";
		String tempPw = "myPw";
		
		if(id.equals(tempId) && pw.equals(tempPw)) {
			response.sendRedirect("/studyProject/chapter04/loginSuccess.html");
		} else {
			response.setStatus(400);
		}
	}

}

 

서버는 로그인에 성공했을 때 포워딩(이동) 경로를 명시해줬음(1)

로그인에 실패했을 때는 400 상태 코드를 응답함(2)

 

이제 요청을 하고 로그인에 실패했을 때 결과를 보여줄 웹 페이지를 만들자

webapp -> chapter04 -> login2.html 을 추가하고 아래 코드를 입력하자

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>로그인</title>
</head>
<body>
	<form action="/studyProject/chapter04/login_2" method="POST">
		아이디: <input type="text" name="id"><br>
		비밀번호: <input type="password" name="pw"><br>
		<input type="submit" value="로그인">
	</form>
</body>
</html>

이 HTML의 경우 별도로 JS 가 없으니 이 HTML 자체에 대한 설명은 생략함

 

서버를 재시작 후 login2.html 페이지에 접속해 아이디, 비밀번호를 입력하고 로그인을 해보자

form 태그로 요청했으므로 브라우저의 URL 이 form 태그의 action 속성에 명시해둔 URL 로 바뀌면서 요청이 들어감

이때 로그인에 성공했다면 서블릿에서는 reseponse.sendRedirect 메서드가 호출되고 이는 서버가 클라이언트에게 "/studyProject/chapter04/loginSuccess.html" 로 이동해 라고 이동할 경로를 지명해주는 것(1)

그러면 브라우저의 URL이 지명해준 URL로 바뀌며 로그인 성공 메세지가 보임

 

그리고 다시 login2.html 페이지에 접속해 아이디, 비밀번호를 myId, myPw가 아닌 것으로 입력하고 로그인을 해보자

form 태그로 요청했으므로 브라우저의 URL 이 form 태그의 action 속성에 명시해둔 URL 로 바뀌면서 요청이 들어감

이때 로그인에 실패했으므로 서블릿에서는 response.status 메서드가 호출되고 이는 서버가 클라이언트에게 400 상태 코드만 응답하는 것

브라우저는 서버로 부터 400 상태 코드만 받게 되므로 이동이 이뤄지지도 않고 별도의 메세지가 보이지 않음


첫 번째 방법 ( JS의 location.href 를 사용 ) 과 두 번째 방법 ( 요청 정보(HttpServletRequest)의 sendRedirect 메서드를 사용 ) 에서 서버 코드의 차이와 클라이언트 코드의 차이를 각각 비교해보자

 

<< 서버 코드의 차이 >>

첫 번째 방법은 클라이언트 사이드 언어인 JS 를 사용해서 포워딩을 하는 방식이므로 서버에서 별도로 지정할 게 없는 것임

두 번째 방법은 서버 사이드 언어인 서블릿을 사용해서 클라이언트에게 "여기로 이동해!" 라고 명시했기 때문에 서버에서 별도로 지정해줘야함

 

<< 클라이언트 코드의 차이 >>

 

첫 번째 방법은 클라이언트 사이드 언어인 JS 를 사용해서 포워딩을 하는 방식이므로 ajax로 요청하고 결과를 받아서 상황에 맞게 포워딩을 하거나 결과를 보여주고 있음

두 번째 방법은 서버 사이드 언어인 서블릿을 사용해서 포워딩 할 곳을 클라이언트가 지명받았기 때문에 클라이언트는 별도의 처리 없이 바로 form 태그로 요청하면 됨

두 번째 방법을 사용하는데 ajax 로 요청하게 되면 로그인에 성공했을 때 로그인 성공 페이지로 이동할 수 없음

ajax 로 요청했을 때 서버가 sendRedirect 로 응답을 하면 ajax 는 응답을 이해하지 못하고 아무 반응을 하지 않음


포워딩의 첫 번째 방법(클라이언트에게 이동할 곳을 지정해주는 방법) 중 세 번째 방법을 알아보자

<< 응답 정보(HttpServletResponse)의 addHeader 메서드를 사용 >>

 

또 다른 로그인 서블릿을 추가하자

chapter04 -> login3 서블릿을 만들고 아래 코드를 입력하자

package chapter04;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/chapter04/login_3")
public class Login3 extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		
		String tempId = "myId";
		String tempPw = "myPw";
		
		if(id.equals(tempId) && pw.equals(tempPw)) {
			response.setStatus(303);
			response.addHeader("location", "/studyProject/chapter04/loginSuccess.html");
		} else {
			response.setStatus(400);
		}
	}

}

 

로그인에 성공했을 때 응답 정보 상태 코드에 303 을 설정하고(1) 응답 정보 헤더에 location="/studyProject/chapter04/loginSuccess.html" 을 담아(2) 응답한 것

 

클라이언트가 전달 받은 응답 정보는 이와 같음

 

"300번대 상태 코드는 클라이언트의 요청을 처리하긴 했지만 처리를 완료하지는 못했다. 처리를 완료하기 위해서는 내가 지명한 곳으로 이동해라." 라는 뜻을 갖고 있는 상태코드임

따라서 브라우저는 300번대 상태 코드를 응답 받게 되면 헤더에 location이 있는지 확인함

헤더에 location이 있다면 location에 담긴 URI 로 이동을 하고 헤더에 location이 없다면 서바가 이동할 곳을 지명해주지 않았기 때문에 이동하지 않고 그 자리 그대로 있음

 

우리는 303번 상태 코드를 설정하고 헤더에 location을 담았기 때문에 브라우저가 해당 경로로 이동함

따라서 로그인에 성공했을 경우 로그인 성공 페이지가 보여짐

 

그러나 로그인에 실패했을 때는 서버가 400 상태 코드를 응답하므로 브라우저는 아무것도 하지 않음


여기까지 포워딩을 하는 큰 두 가지 방법

1. 클라이언트에게 이동할 곳을 지정해주는 방법

2. 서버 안에서 이동하는 방법

중 클라이언트에게 이동할 곳을 지정해주는 방법의 세 가지 방법을 알아봤음

1. JS의 location.href 를 사용

2. 요청 정보(HttpServletRequest)의 sendRedirect 메서드를 사용

3. 응답 정보(HttpServletResponse)의 addHeader 메서드를 사용

 

여기서 자주 사용하는 방법은 1, 2번 방법이고 3번은 자주 사용하지는 않음

 

1번은 언제 사용할까? 클라이언트의 잘못으로 클라이언트의 요청이 실패할 수 있을 경우

2번은 언제 사용할까? 클라이언트의 요청에 대한 결과 페이지가 무조건 있을 경우

 

1번의 경우는 회원가입, 로그인 등을 예로 들 수 있음

회원가입을 할 때 일반적으로 아이디, 연락처, 이메일 등은 누군가 이미 사용 중이라면 사용할 수 없음

보통은 아이디를 입력하고 중복 확인을 별도로 하지만 중복 확인을 하는 시점에는 아무도 사용하지 않는 아이디였는데 [ 회원 가입 ] 버튼을 누르는 시점에서는 누군가 사용할 수도 있음

극단적인 예를 들어보면 어느 사이트에 회원 가입을 하는데 아이디 중복 확인까지 마쳤음

이때는 사용중이지 않은 아이디였다고 나왔음

그 후 [ 회원 가입 ] 버튼을 누르기 직전에 갑자기 부모님께서 심부름을 시켜서 심부름을 갔다 왔다고 해보자

그러면 그 사이 누군가 내가 중복 확인할 때 입력했던 아이디로 가입을 했을 수 있음

나는 그러한 사실을 모르고 그대로 [ 회원 가입 ] 버튼을 누를 것

그러면 회원 가입하는 시점에 이미 사용중인 아이디가 됐으므로 회원 가입에 실패하게 됨

이런 상황이 1번의 상황(클라이언트의 잘못으로 클라이언트의 요청이 실패할 수 있을 경우)임

이때 내가 다시 아이디를 다른 아이디로 입력하고 중복 확인 후 곧바로 회원가입을 한다면 회원 가입이 성공할 것

 

또는 로그인을 예로 들어보자, 특히나 요즘 공감할 수 있는 예임

점점 보안 관련 사항 때문에 비밀번호를 더 복잡하게 만들어야하고 이전에 사용했던 비밀번호는 사용하지 못함

그래서 내가 A 사이트와 B 사이트 계정의 비밀번호를 서로 다르게 해놓은 상태임

A 사이트의 비밀번호는 1111 이고 B 사이트의 비밀번호는 2222임

그런 상황에서 A 사이트에 접속할때 실수로 비밀번호를 2222 로 입력하고 로그인을 하려 했다면 나(클라이언트)의 실수로 로그인에 실패하게 됨

그럴 경우 화면에 "아이디 또는 비밀번호를 확인해주세요" 라는 문구가 보임

그 후 비밀번호를 1111 로 바꾸고 로그인을 하면 로그인에 성공할 것

이렇게 클라이언트의 어떤 잘못이나 실수로 클라이언트의 요청이 실패할 수 있고 또는 성공할 수 있을 때 1번의 방법(JS의 location.href 를 사용) 으로 요청을 처리함

 

2번의 경우는 검색을 예로 들 수 있음

네이버에 "칼국수" 를 검색하고 싶은데 실수로 "갈국수" 로 입력하고 검색 버튼을 눌렀다고 하자

그렇다고 "칼국수" 라고 다시 입력하세요 라는 문구가 보일까? 아님

그대로 갈국수의 결과가 보임

검색처럼 사용자가 원하는 결과를 무조건 보여줘야할 때 2번의 방법(요청 정보(HttpServletRequest)의 sendRedirect 메서드를 사용) 으로 요청을 처리함

 

그러나 반드시 그런것만은 아니니 이런 기준으로 이해하고 사용하다 보면 여러분만의 기준이 생길 것

 

2번 대신에 3번의 방법으로 요청을 처리할 수도 있지만 그건 여러분이 경험이 더 쌓이면 판단할 수 있을 것

 

만약에 실제로 개발할 때 이런 예가 와닿지 않는다면 직접 1번 또는 2번의 방법만을 사용해서 개발을 해보자 그러면 어느 순간 또 다른 방법이 필요하다는걸 분명히 느끼게 될 것

728x90
LIST