본문 바로가기
Programming/Jsp

[JSP/Servlet] HTTP Redirect / Dispatcher (forward, include)

by prinha 2020. 7. 21.
반응형
반응형

 

HTTP 리다이렉트(Redirect)란?

're + direct / 다시 지시하다'라는 의미

예를 들어 브라우저가 www.test.com/page1 URL을 웹 서버에 요했을때

서버는 HTTP 응답 메시지를 통해 "www.test.com/page2 로 다시 요청하세요~" 라고

브라우저에게 다른 URL(길, 방향) 을 지시할 수 있음

 

 

-> HTTP 리다이렉트는 HTTP표준으로 정의되어있는데 최초 요청을 받은 웹서버는 HTTP 응답 상태코드로 302를 보내고

응답 메시지 헤더 중 Location값으로 리다이렉트 되어야 할 주소를 설정해 리턴한다.

브라우저 등의 웹 클라이언트는 HTTP 응답 메시지의 상태코드가 302라는 것을 보고

리다이렉트라는 것을 인지하여 Location에 설정되어있는 URL로 다시 재요청한다.

 

-> 리다이렉트가 필요한 이유

ex)어떤 글의 URL을 알아내어 브라우저의 주소창에 입력한 후 접근한다고 했을 때 권한이 없으면 해당 내용을 웹서버가 응답하면 안됨.

      이때 웹서버는 글에 접근하는 요청마다 권한을 검사하고 권한이 되지 않을 경우 경고 메시지를 보내고, 

      로그인 되지 않은 상태라면 로그인 페이지로 리다이렉트 시킬 필요가 있음

 

출처: https://dololak.tistory.com/147 [코끼리를 냉장고에 넣는 방법]


Servelt에서 특정 URL이나 페이지로 이동하게 하는 방식

1. Redirect방식 -> sendRedirect() : 이동하기

클라이언트 요청시 완전히 새로운 페이지로 이동해서 기존 데이터를 하나도 사용할 수 없는 방식으로

포워딩 될 때 브라우저의 주소 표시줄의 URL이 변경된다

(포워딩된 jsp페이지에서는 서블릿에서 request영역에 공유한 속성값에 접근 불가능)

request.setAttribute("request", "requestValue");
response.sendRedirect("redirect.jsp//이동할 페이지");

// redirect.jsp에서
request 속성 값 : <%=request.getAttribute("request") %> // null

 

예제) 사용자가 page1.jsp를 요청한 경우 page2.jsp로 리다이렉트 시켜보기 : response.sendRedirect(String url)

<%-- page1.jsp --%>

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
<%
  String id = request.getParameter("id"); 
  response.sendRedirect("http://localhost:8080/myApp/page2.jsp?id="; + id); 
%>
<%-- page2.jsp --%>

<%@ page language="java" contentType="text/html; charset=UTF-8"         
     pageEncoding="UTF-8"%> 
<%
     //브라우저가 리다이렉트를 통해 다시 요청한 파라미터 값 
     String id = request.getParameter("id"); 
%>    

당신의 id는 <%= id %> 입니다. 

-> 예제 테스트 결과 : 당신의 id는 test입니다.

    브라우저로 (http://localhost:8080/myApp/page1.jsp?id=test) 요청했으나

    주소 표시줄의 URL이 page2.jsp(http://localhost:8080/myApp/page2.jsp?id=test) 로 바뀌고

    실제 보여지는 페이지는 page2.jsp이다. -> 리다이렉트 성공


2. Dispatcher방식 -> forward() : 전달하기     // 주로 MVC 패턴의 웹사이트 개발시 핵심적인 역할

클라이언트 요청시 전송한 (기존)데이터를 그대로 유지하는 방식으로

포워딩이 되더라도 주소가 변경되지 않음 ( 같은 request 영역 공유 - 속성값 접근 가능 )

// 1. ServletContext를 통한 생성 방법

// 호출 대상을 web.xml에 지정한 서블릿 이름으로 지정
ServletContext context = this.getServletContext(); 
RequestDispatcher dispatcher = context.getNamedDispatcher("helloServlet"); 

// 호출 대상을 URL경로로 지정, 웹어플리케이션 루트경로를 기준으로 절대경로만 지정 가능
ServletContext context = this.getServletContext(); 
RequestDispatcher dispatcher = context.getRequestDispatcher("/hello");      


// 2. ServletRequest를 통해서 얻는 방법
// URL 경로를 통해서 대상을 지정하는 한가지 방법만 제공
RequestDispatcher dispatcher = request.getRequestDispatcher("/hello");  

 

RequestDispatcher

HttpServletResponse를 사용하면 sendRedirect() 메소드를 이용하여 지정한 경로로 이동시킬 수 있으나,

sendRedirect()는 HTTP 리다이렉션을 이용하기때문에 하나의 요청 범위 안에서 처리를 하는것이 아니라

브라우저에게 Response후 브라우저측에서 지정받은 요청 경로로 다시 재요청하는 방식이기에 두번의 HTTP 트랜잭션이 발생한다. 

서버측에서는 최초의 받은 요청중에 처리한 내용을 리다이렉트된 요청안에서 공유할 수 없는 문제가 있다.

 

물론 sendRedirect() 메소드도 쿠키, 세션을 이용해 특정 상태를 유지할 수는 있으나

상황에 따라 제한적이고, 다양한 한계가 있기 때문에 좋은 방법이 아니다.

 

HttpServletResponse를 통해 리다이렉트하는 방식은 현재 어플리케이션 이외에 다른 자원의 경로를 요청할 수 있는 반면

RequestDispatcher는 현재 처리중인 서블릿이 속해 잇는 웹 어플리케이션 내에서만 요청을 제어할 수 있다.

 

 

 

 

 

forward() 메소드

HttpServletResponse를 사용하면 sendRedirect() 메소드는 대상 자원으로 제어를 넘기는 역할을 한다.

브라우저에서 /a.jsp로 요청했을때 /a.jsp에서 forward()를 실행하여 /b.jsp로 제어를 넘길 수 있다.

제어를 넘겨받은 /b.jsp는 처리 결과를 최종적으로 브라우저에서 출력한다.

-> 브라우저 입장에서는 /a.jsp를 요청했지만 /b.jsp의 결과를 받았음

-> 이때 HTTP리다이렉트 방식과는 달리 하나의 HTTP요청(request) 범위 안에서 동작이 이루어짐

-> 제어를 넘기기 이전에 출력 버퍼를 비우기때문에 a.jsp -> b.jsp로 호출시

    a.jsp에서 어떤 내용을 버퍼에 출력했더라도 무시되며 제어가 넘어간 b.jsp의 출력 내용만 브라우저에 전달됨

 

 

예제) forward() 메소드

 

Dispatch Test(/dispatch) -> HelloServlet(/hello)로 forward()

forward()는 특정 자원(Servlet or JSP)으로 제어를 넘기는데 예제는 서블릿이지만 JSP페이지에서도

application이나 request 내장 객체를 통해서 RequestDispatcher를 얻어 실행할 수 있음.

 

public class DispatchTest extends HttpServlet { 
     @Override 
     protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                    throws ServletException, IOException { 
           request.setCharacterEncoding("UTF-8"); 
           request.setAttribute("name", "doloak"); //사전처리 
           
           RequestDispatcher dispatcher = request.getRequestDispatcher("/hello"); 
           dispatcher.forward(request, response); 
     }
}
public class HelloServlet extends HttpServlet { 
     @Override 
     protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                    throws ServletException, IOException { 
        response.setContentType("text/html; charset=utf-8"); 
 
 
        PrintWriter out = response.getWriter(); 
        out.println("<HTML>"); 
        out.println("<head><title>HELLO</title></head>"); 
        out.println("<body>"); 
        out.println("HELLO " + request.getAttribute("name")); 
        out.println("</body>"); 
        out.println("</html>"); 
     }
}
// JSP페이지에서 사용시-기본 객체들 이용
<%
    RequestDispatcher dispatcher = application.getRequestDispatcher("/hello");            
    dispatcher.forward(request, response);
%>

 


 

3. RequestDispatcher의 include() - 포함하기

처리 흐름 제어를 특정 대상에게 넘기고 대상이 처리한 결과를 현재 페이지에 포함시키는 기능

forward() 메소드와 달리 include() 메소드는 제어를 넘긴 대상 페이지의 처리가 완료 되면

처리 결과와 함께 원래 페이지로 제어가 돌아오고 이후 나머지 처리를 하게 된다.

즉, forward() 메소드는 포워딩된 대상 페이지가 최종 결과를 출력했다면

include()메소드는 최초 흐름이 시작된 페이지(a.jsp)가 브라우저로 최종 결과를 출력한다.

 

public void include(ServletRequest request,  ServletResponse response) throws ServletException, IOException;

 

 

include() 호출시에는 HttpServletRequest와 HttpServletResponse를 매개변수로 넘겨주는데, 이 두가지 객체를 호출하는 페이지와 호출받는 쪽에서 공유하기때문에 데이터를 두 개의 객체에 담아 서로 공유

 

 

브라우저로 데이터를 출력하는 출력스트림도 하나의 객체를 공유하므로 출력 결과를 포함시키는 것처럼 보임 include()는 출력버퍼를 비우지않기때문에 호출하는 페이지에서 출력하는 내용에 이어서 호출되는 페이지에서 출력하는 내용까지 포함시킬 수 있음

 

반응형