ServletFilter의 ServletResponse에서 HTTP 상태 코드를 얻으려면 어떻게해야합니까?
내 웹 앱에서 반환 된 모든 HTTP 상태 코드에 대해보고하려고합니다. 그러나 ServletResponse를 통해 또는 HttpServletResponse로 캐스팅하더라도 상태 코드에 액세스 할 수없는 것으로 보입니다. ServletFilter 내에서이 값에 액세스하는 방법이 있습니까?
먼저 접근 가능한 장소에 상태 코드를 저장해야합니다. 응답을 구현으로 래핑하고 유지하는 것이 가장 좋습니다.
public class StatusExposingServletResponse extends HttpServletResponseWrapper {
private int httpStatus;
public StatusExposingServletResponse(HttpServletResponse response) {
super(response);
}
@Override
public void sendError(int sc) throws IOException {
httpStatus = sc;
super.sendError(sc);
}
@Override
public void sendError(int sc, String msg) throws IOException {
httpStatus = sc;
super.sendError(sc, msg);
}
@Override
public void setStatus(int sc) {
httpStatus = sc;
super.setStatus(sc);
}
public int getStatus() {
return httpStatus;
}
}
이 래퍼를 사용하려면보고를 수행 할 수 있다면 서블릿 필터를 추가해야합니다.
public class StatusReportingFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
StatusExposingServletResponse response = new StatusExposingServletResponse((HttpServletResponse)res);
chain.doFilter(req, response);
int status = response.getStatus();
// report
}
public void init(FilterConfig config) throws ServletException {
//empty
}
public void destroy() {
// empty
}
}
Servlet 3.0부터 HttpServletResponse#getStatus()
.
따라서 업그레이드 할 여지가 있다면 Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 등)으로 업그레이드하고 래퍼가 필요하지 않습니다.
chain.doFilter(request, response);
int status = ((HttpServletResponse) response).getStatus();
또한 #sendRedirect에 대한 래퍼를 포함해야하며 상태를 '0'이 아닌 '200'으로 초기화하는 것이 좋습니다.
private int httpStatus = SC_OK;
...
@Override
public void sendRedirect(String location) throws IOException {
httpStatus = SC_MOVED_TEMPORARILY;
super.sendRedirect(location);
}
위의 David의 답변에서 누락 된 한 가지는 다른 형태의 sendError도 재정의해야한다는 것입니다.
@Override
public void sendError(int sc, String msg) throws IOException {
httpStatus = sc;
super.sendError(sc, msg);
}
David의 답변 외에도 reset 메서드를 재정의하고 싶을 것입니다.
@Override
public void reset() {
super.reset();
this.httpStatus = SC_OK;
}
...뿐만 아니라 더 이상 사용되지 않는 setStatus (int, String)
@Override
public void setStatus(int status, String string) {
super.setStatus(status, string);
this.httpStatus = status;
}
HttpServletResponseWrapper를 작성하고 모든 setStatus (), sendError () 및 sendRedirect () 메서드를 재정 의하여 모든 것을 기록합니다. 모든 요청에서 응답 객체에 대한 래퍼를 교체하는 필터를 작성하십시오.
이전 컨테이너를 사용하는 경우 실제 상태 코드를 사용하는 David Rabinowitz의 대체 솔루션 (래퍼를 사용하여 설정된 후 변경되는 경우)은 다음과 같습니다.
public class StatusExposingServletResponse extends HttpServletResponseWrapper {
public StatusExposingServletResponse(HttpServletResponse response) {
super(response);
}
@Override
public void sendError(int sc) throws IOException {
super.sendError(sc);
}
@Override
public void sendError(int sc, String msg) throws IOException {
super.sendError(sc, msg);
}
@Override
public void setStatus(int sc) {
super.setStatus(sc);
}
public int getStatus() {
try {
ServletResponse object = super.getResponse();
// call the private method 'getResponse'
Method method1 = object.getClass().getMethod("getResponse");
Object servletResponse = method1.invoke(object, new Object[] {});
// call the parents private method 'getResponse'
Method method2 = servletResponse.getClass().getMethod("getResponse");
Object parentResponse = method2.invoke(servletResponse, new Object[] {});
// call the parents private method 'getResponse'
Method method3 = parentResponse.getClass().getMethod("getStatus");
int httpStatus = (Integer) method3.invoke(parentResponse, new Object[] {});
return httpStatus;
}
catch (Exception e) {
e.printStackTrace();
return HttpServletResponse.SC_ACCEPTED;
}
}
public String getMessage() {
try {
ServletResponse object = super.getResponse();
// call the private method 'getResponse'
Method method1 = object.getClass().getMethod("getResponse");
Object servletResponse = method1.invoke(object, new Object[] {});
// call the parents private method 'getResponse'
Method method2 = servletResponse.getClass().getMethod("getResponse");
Object parentResponse = method2.invoke(servletResponse, new Object[] {});
// call the parents private method 'getResponse'
Method method3 = parentResponse.getClass().getMethod("getReason");
String httpStatusMessage = (String) method3.invoke(parentResponse, new Object[] {});
if (httpStatusMessage == null) {
int status = getStatus();
java.lang.reflect.Field[] fields = HttpServletResponse.class.getFields();
for (java.lang.reflect.Field field : fields) {
if (status == field.getInt(servletResponse)) {
httpStatusMessage = field.getName();
httpStatusMessage = httpStatusMessage.replace("SC_", "");
if (!"OK".equals(httpStatusMessage)) {
httpStatusMessage = httpStatusMessage.toLowerCase();
httpStatusMessage = httpStatusMessage.replace("_", " ");
httpStatusMessage = capitalizeFirstLetters(httpStatusMessage);
}
break;
}
}
}
return httpStatusMessage;
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
private static String capitalizeFirstLetters(String s) {
for (int i = 0; i < s.length(); i++) {
if (i == 0) {
// Capitalize the first letter of the string.
s = String.format("%s%s", Character.toUpperCase(s.charAt(0)), s.substring(1));
}
if (!Character.isLetterOrDigit(s.charAt(i))) {
if (i + 1 < s.length()) {
s = String.format("%s%s%s", s.subSequence(0, i + 1),
Character.toUpperCase(s.charAt(i + 1)),
s.substring(i + 2));
}
}
}
return s;
}
@Override
public String toString() {
return this.getMessage() + " " + this.getStatus();
}
}
Warning: lots of assumptions of the class hierarchy when using sneaky reflection and introspection to get to private data values.
'Development Tip' 카테고리의 다른 글
JQuery의 텍스트 필드 값 지우기 (0) | 2020.12.02 |
---|---|
Unix 쉘 스크립트에서 현재 날짜를 epoch로 가져옵니다. (0) | 2020.12.02 |
Angular.js 클릭시 요소 CSS 클래스를 변경하고 다른 모든 요소를 제거하는 방법 (0) | 2020.12.02 |
jQuery Uncaught TypeError : 정의되지 않은 'fn'속성 (익명 함수)을 읽을 수 없습니다. (0) | 2020.12.02 |
세분화 오류 : OS X에서 11 (0) | 2020.12.01 |