위의 이미지를 설명하면, 리다이렉트는 클라이언트가 redirect01.jsp를 요청했더니 웹서버로부터 반환된 내용에 리다이렉트 내용이 있어서 웹서버로 다시 요청, 웹서버에서 최종적으로 redirect02.jsp를 반환하는 과정이다.
리다이렉트를 현실에서 비유를 들자면, 휴대폰 관련 상담을 위해 고객상담센터에 연락을 했다고 가정해보자. 휴대폰 보험 관련 문의를 위해 고객상담센터에 전화했더니 센터에서는 해결을 못하니 보험 회사로 직접 연락하라며 번호를 알려주었다. 이 번호로 다시 연락해서 보험 상담원과 연결이 되었다.
이렇게 클라이언트가 처음 요청과 다른 요청을 해서 2번의 요청을 통해 연결되는 상황을 리다이렉트라고 할 수 있다.
결과적으로 브라우저를 통해 페이지 로드가 한 번 되는것처럼 보이지만, 사실은 클라이언트와 웹서버간 통신이 각각 2번씩 이뤄진다는 점 이다. 클라이언트가 웹서버에 2번의 요청을 하는 것이다.
서블릿 클래스를 생성한 예제 코드이다. /redirect-first 라는 API로 요청이 들어오면, HttpServletResponse의 sendRedirect()를 이용하여 /redirect-second API로 요청을 리다이렉트하는 코드이다. 결국 화면에 Hello Servlet 02가 출력된다.
HttpServletResponse의 sendRedirect()에 대해 더 알아보자.
아래 포워드에서 비교해서 알 수 있겠지만, 리다이렉트는 sendRedirect() 함수가 호출되는 시점에 페이지를 바로 이동하는게 아니라 서블릿 클래스 내에 코드가 모두 실행되고 반환될 때, 웹서버의 서블릿 클래스가 클라이언트의 요청을 바꿔서 다시 요청받는거다.
HTTP Header의 Status Code를 301(Permanently) 또는 302(Temporarily)로 바꿔서 반환한다. 그래서 바뀐 Header값으로 클라이언트가 웹서버에 재요청하여 다른 페이지를 반환받는 것이다. 이게 리다이렉트 과정이다.
Forward
포워드는 클라이언트가 웹서버에 forward01.jsp를 요청했더니 forward01.jsp에서 작성된 코드에의해 포워딩되어 forward02.jsp를 반환하는걸 의미한다. 결과적으로 위에서 설명한 리다이렉트와 비슷하지만, 클라이언트와 서버간 통신이 각각 1번씩이라는 점에서 다르다.
이번에도 현실에서 비유를 들어보겠다. 고객상담센터에 전화를 걸어서 요금 관련 문의를 했더니, 잠시만 기다려달라고 하더니 저절로 요금 관련 상담원으로 전화연결이 바뀌었다. 전화를 끊고 다시 한것도 아닌데 고객상담센터에서 내 전화를 요금 관련 상담원으로 연결해준 것이다.
이처럼 클라이언트는 한 번의 요청을 했지만, 서버에서 페이지를 바꿔서 반환하는 것을 포워딩이라고 한다.
포워드는 다른 서버와는 할 수 없고, 클라이언트가 처음 요청한 서버내에서 다른 클래스를 전달할 수 있다. 또한 포워딩하는 과정에서 처음 요청받은 서블릿 클래스의 request와 response도 함께 포워딩할 수 있다는 특징이 있다.
protectedvoidservice(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>form</title></head>"); out.println("<body>"); int rand = (int)request.getAttribute("rand"); out.println("랜덤 수 : "+rand); out.println("</body>"); out.println("</html>"); } }
/front 로 요청이 들어오면, FrontServlet.class 에서 랜덤 숫자를 생성했다. 이렇게 생성한 숫자를 포워딩할 클래스에 보내려면, HttpServletRequest의 setAttribute()와 RequestDispatcher의 forward()를 사용해야한다.
1 2
int randNum = (int)(Math.random() * 6) +1; req.setAttribute("rand", randNum);
생성된 랜덤 숫자를 “rand”라는 이름으로 attribute에 넣는다. 이렇게 저장된 attribute를 포워딩하는 서블릿 클래스로 보낼때 사용하는 객체가 RequestDispatcher이다.
/forward 로 요청을 포워딩하는 RequestDispatcher를 생성하고, RequestDispatcher의 forward() 파라미터에 request와 response를 넣으면, 포워딩되는 클래스에 request와 response를 함께 보내준다. 이 request 객체에 attribute가 있기 때문에 RequestDispatcher.forward() 파라미터에 request와 response를 주입하는 것이다.
1 2 3 4 5 6
response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter();
int rand = (int)request.getAttribute("rand"); out.println("랜덤 수 : "+rand);
그럼 포워딩되는 서블릿 클래스에서 API 요청을 받아서 랜덤숫자가 저장된 attribute를 화면에 출력하는 코드이다.
RequestDispatcher 객체는 HttpServletRequest에서 제공하는 객체며, forward()와 include() 2개의 메서드를 가지고 있다.