본문 바로가기
IT만들기/Java

jsp 에러페이지 만들기

by 커피향처럼 2017. 7. 10.

전자정부 프레임워크 샘플 구조에 대한 글을 적다가 에러페이지에 대한 설명을 먼저 해야 할거 같아서
JAVA WAS의 jsp 에러 페이지 설정에 대한 글을 적어봅니다.

웹 개발중에 가장 많이 발생하는 오류는 보통 아래와 같을 겁니다.

404에러 : Not Found 오류로 URL 오타로 많이 보았을 에러 일겁니다. 서비스에 없는 페이지. 없는 URL을 접근 할때 발생합니다.
500에러 : Internal Server Error. 서버 내부 오류로 웹 서버에서 여러가지 원인으로 오류가 발생하게 되면 503에러로 표시됩니다. 끄덕하면 표시 되는 에러죠?

WAS에 에러 페이지 설정이 안되어 있으면 아래 그림처럼 에러코드와 메세지가 출력됩니다.
고의적으로 index를 indxe로 오타를 내서 접속해봤습니다.

404, 500 에러 내용을 접속하는 사람이 모두 봐도 상관 없다면 별다른 설정은 필요 없겠지만 예쁜(?) 메세지를 출력 한다거나 하고자 하면 설정을 해야 겠죠.
에러페이지를 예쁜 페이지를 만드는 것보다 중요한 것은 개발 프로젝트를 할 때 위 그림과 같이 에러 코드, 에러 메세지를 출력하는 것은 시큐어 코딩, 보안에 위반 되기 때문에 웹 페이지에 에러 내용을 출력하는 것은 문제가 됩니다. 무조건 에러 페이지는 어떤 형태든 만들어 주어야 합니다.
만약 에러 페이지 설정을 하지 않는다면 SQL 에러 내용 등, 에러의 자세한 내용이 표시 되기도 합니다. 이럴 경우 해킹의 타겟이 되기도 하죠. 

에러 페이지 설정을 하도록 하겠습니다.
이 방법은 서블릿 2.3 버전에서부터 생긴 방법으로 그 이하 방법은 아래에 다시 설명을 하도록 하겠습니다.
아파치 톰캣 6 등의 버전에서 사용 가능합니다.
web.xml 파일에 error page 설정이 없다면 아래와 같이 <web-app>와 </web-app> 태그 사이에 에러 페이지 설정을 넣어줍니다.

exception-type으로 Exception의 유형별로 에러 페이지를 설정할 수 있고 error-code로 에러 코드별로 에러 페이지를 지정하여 사용 할 수 있습니다.
위의 예는 "/common/error.jsp"로 하였는데 Controller.java 파일의 RequestMapping 설정 등으로 /common/error.do"와 같이 사용도 가능합니다.
webapp/common/error.jsp 파일을 다음과 같이 만들어 봅니다."

<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ko" xml:lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>error</title>
</head>
<body>
    <table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0">
        <tr>
            <td width="100%" height="100%" align="center" valign="middle" style="padding-top: 150px;">
            잘못된 경로로 접근하였습니다.
            </td>
        </tr>
    </table>
</body>
</html>

"http://localhost:8080/HelloWorld/a.do"를 웹브라우저에 URL을 호출해 보겠습니다.

위와 같이 없는 페이지로 접근하였더니 404 에러 페이지가 아니라 우리가 만든 에러 페이지가 화면에 출력됩니다.

* 개발 환경의 jsp 에러 페이지 만들기
웹 개발시에 이클립스의 console 창으로 출력된 에러 메시지를 봐도 되겠지만 에러 페이지에 에러 내용을 출력하도록 수정을 해보겠습니다.
에러 내용을 출력하는 에러 페이지를 절대 운영 환경에 적용하면 안됩니다. 시큐어 코딩 위반임을 주의해야 합니다.
참고로 2017년 행정자치부 시큐어 코딩 가이드에서 기존에 많이 사용하였던 LOGGER.error(e.getMessage())와 같은 방법으로 에러 내용을 로그 파일에 출력 가능 했던 부분이 LOGGER.error("기능A 오류 발생")와 같이 정적 메세지로 출력해야만 하도록 변경 되었습니다. 로그에도 에러내용을 출력하면 안되도록 시큐어 코딩이 강화되었습니다.

 <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ko" xml:lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>error</title>
</head>
<body>
    <table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0">
        <tr>
            <td width="100%" height="100%" align="center" valign="middle" style="padding-top: 150px;">
            code : ${requestScope['javax.servlet.error.status_code']}<br/>
            exception type : ${requestScope['javax.servlet.error.exception_type']}<br/>
            message : ${requestScope['javax.servlet.error.message']}<br/>
            exception : ${requestScope['javax.servlet.error.exception']}<br/>
            request uri : ${requestScope['javax.servlet.error.request_uri']}<br/>
            servlet name : ${requestScope['javax.servlet.error.servlet_name']}<br/>
            </td>
        </tr>
    </table>
</body>
</html>

서블릿 2.3 미만에서 사용했던 <%= exception.getMessage() %>와 같이 exception 객체는 사용 못하는 점을 주의해 주세요.

javax.servlet.error.status_code
이 속성은 java.lang.Integer 데이터 유형에 저장 한 후에 저장하고 분석 할 수있는 상태 코드를 제공합니다.
 
javax.servlet.error.exception_type
이 속성은 java.lang.Class 데이터 유형에 저장 한 후에 저장하고 분석 할 수있는 예외 유형에 대한 정보를 제공합니다.

javax.servlet.error.message
이 속성은 java.lang.String 데이터 유형에 저장 한 후 저장하고 분석 할 수있는 정확한 오류 메시지에 대한 정보를 제공합니다.

javax.servlet.error.request_uri
이 속성은 서블릿을 호출하는 URL에 대한 정보를 제공하며 java.lang.String 데이터 유형에 저장 한 후 저장 및 분석 할 수 있습니다.

javax.servlet.error.exception
이 속성은 저장 및 분석 할 수있는 예외에 대한 정보를 제공합니다.

javax.servlet.error.servlet_name
이 속성은 java.lang.String 데이터 유형에 저장 한 후에 저장하고 분석 할 수있는 서블릿 이름을 제공합니다.


위와 같이 수정 후 SQL 오류를 강제로 발생 시켜 보았습니다.
 

에러 출력이 지저분하긴 하지만 어떤 에러인지 찾아보세요.~~
만약 전자정부 프레임워크로 기본 샘플 프로젝트를 생성해서 SQL 관련 오류를 발생시킨다면 위와 같이 에러 페이지가 보이지 않을 겁니다.

 

src/main/webapp/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml 파일에 SQL 에러 페이지가 설정되어 있기 때문에 이 부분을 제거하거나 수정해주어야 합니다. 
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="cmmn/egovError"/>
        <property name="exceptionMappings">
            <props>
                <prop key="org.springframework.dao.DataAccessException">cmmn/dataAccessFailure</prop>
                <prop key="org.springframework.transaction.TransactionException">cmmn/transactionFailure</prop>
                <prop key="egovframework.rte.fdl.cmmn.exception.EgovBizException">cmmn/egovError</prop>
                <prop key="org.springframework.security.AccessDeniedException">cmmn/egovError</prop>
            </props>
        </property>
    </bean> 

    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" p:order="1"
     p:viewClass="org.springframework.web.servlet.view.JstlView"
     p:prefix="/WEB-INF/jsp/egovframework/example/" p:suffix=".jsp"/>

 

위의 <bean> 두 부분을 합쳐서 보게 되면 DataAccessException 에러가 발생되면 "/WEB-INF/jsp/egovframework/example/cmmn/dataAccessFailure.jsp" 파일을 출력하도록 설정되어 있습니다.
 

 

* 서블릿 2.3 미만 버전에서 에러 페이지 설정 방법
jsp 페이지에 "<%@ page errorPage="error.jsp" %>" 부분을 추가하고 "error.jsp" 파일에는 "<%@ page isErrorPage="true" %>"라는 문장을 넣어주어야 합니다.
에러 타입: <%= exception.getClass().getName() %>
에러 메시지: <b><%= exception.getMessage() %>
이와 같은 코딩으로 에러 상세 메세지를 화면에 출력 할 수 있습니다.
위에서도 언급하였지만 실제 서비스 시에는 절대 사용하면 안됩니다. 에러 페이지에는 "잘못된 경로로 접근하였습니다." 등의 고정된 메세지만을 출력해서 에러 원인에 대한 힌트를 절대 노출되지 않도록 해야 합니다

웹 에러 및 상태 코드입니다. 참고하세요.
100 상태 코드 : Continue
101 상태 코드 : Switching protocols
200 상태 코드  : OK, 에러없이 전송 성공
201 상태 코드  : Created, POST 명령 실행 및 성공
202 상태 코드  : Accepted, 서버가 클라이언트 명령을 받음
203 상태 코드 : Non-authoritative information, 서버가 클라이언트 요구 중 일부 만 전송
204 상태 코드 : No content, 클라언트 요구을 처리했으나 전송할 데이터가 없음
205 상태 코드 : Reset content
206 상태 코드 : Partial content
300 상태 코드 : Multiple choices, 최근에 옮겨진 데이터를 요청
301 상태 코드 : Moved permanently, 요구한 데이터를 변경된 임시 URL에서 찾았음
302 상태 코드 : Moved temporarily, 요구한 데이터가 변경된 URL에 있음을 명시
303 상태 코드 : See other, 요구한 데이터를 변경하지 않았기 때문에 문제가 있음
304 상태 코드 : Not modified
305 상태 코드 : Use proxy
400 상태 코드 : Bad request, 클라이언트의 잘못된 요청으로 처리할 수 없음
401 상태 코드 : Unauthorized, 클라이언트의 인증 실패
402 상태 코드 : Payment required, 예약됨
403 상태 코드 : Forbidden, 접근이 거부된 문서를 요청함
404 상태 코드 : Not found, 문서를 찾을 수 없음
405 상태 코드 : Method not allowed, 리소스를 허용안함
406 상태 코드 : Not acceptable, 허용할 수 없음
407 상태 코드 : Proxy authentication required, 프록시 인증 필요
408 상태 코드 : Request timeout, 요청시간이 지남
409 상태 코드 : Conflict
410 상태 코드 : Gone, 영구적으로 사용할 수 없음
411 상태 코드 : Length required
412 상태 코드 : Precondition failed, 전체조건 실패
413 상태 코드 : Request entity too large,
414 상태 코드 : Request-URI too long, URL이 너무 김
415 상태 코드 : Unsupported media type
500 상태 코드 : Internal server error, 내부서버 오류(잘못된 스크립트 실행시)
501 상태 코드 : Not implemented, 클라이언트에서 서버가 수행할 수 없는 행동을 요구함
502 상태 코드 : Bad gateway, 서버의 과부하 상태
503 상태 코드 : Service unavailable, 외부 서비스가 죽었거나 현재 멈춤 상태
504 상태 코드 : Gateway timeout
505 상태 코드 : HTTP version not supported

댓글