wake-up-neo.net

Wie kann ich den HTTP-Statuscode aus einer ServletResponse in einem ServletFilter abrufen?

Ich versuche, jeden HTTP-Statuscode zu melden, der von meiner Webapp zurückgegeben wird. Der Statuscode scheint jedoch nicht über die ServletResponse zugänglich zu sein oder selbst wenn ich ihn in eine HttpServletResponse umwandle. Gibt es eine Möglichkeit, auf diesen Wert in einem ServletFilter zuzugreifen?

58
Seth Weiner

Zunächst müssen Sie den Statuscode an einem zugänglichen Ort speichern. Am besten verpacken Sie die Antwort mit Ihrer Implementierung und halten Sie sie dort:

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;
    }

}

Um diesen Wrapper verwenden zu können, müssen Sie einen Servlet-Filter hinzufügen, wo Sie Ihre Berichte erstellen können:

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
    }

}
83

Seit Servlet 3.0 gibt es eine HttpServletResponse#getStatus() .

Wenn also ein Upgrade möglich ist, sollten Sie ein Upgrade auf Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 usw.) durchführen, und Sie benötigen keinen Wrapper.

chain.doFilter(request, response);
int status = ((HttpServletResponse) response).getStatus();
61
BalusC

Sie müssen außerdem einen Wrapper für #sendRedirect einschließen, und es ist besser, den Status auf '200' anstatt auf '0' zu initialisieren.

private int httpStatus = SC_OK;

...

@Override
public void sendRedirect(String location) throws IOException {
    httpStatus = SC_MOVED_TEMPORARILY;
    super.sendRedirect(location);
}
16
Joel Hockey

Was in Davids Antwort oben fehlt, ist, dass Sie auch die andere Form von sendError überschreiben sollten:

@Override
public void sendError(int sc, String msg) throws IOException {
    httpStatus = sc;
    super.sendError(sc, msg);
}
12
William Rose

Neben Davids Antwort sollten Sie auch die Rücksetzmethode überschreiben:

@Override
public void reset() {
    super.reset();
    this.httpStatus = SC_OK;
}

... sowie der veraltete setStatus (int, String)

@Override
public void setStatus(int status, String string) {
    super.setStatus(status, string);
    this.httpStatus = status;
}
8
Grégory Joseph

Schreiben Sie einen HttpServletResponseWrapper, und überschreiben Sie alle Methoden setStatus (), sendError () und sendRedirect (), um alles zu protokollieren. Schreiben Sie einen Filter, der Ihren Wrapper bei jeder Anforderung in das Antwortobjekt einlagert.

6
Licky Lindsay

Wenn Sie mit einem älteren Container stecken bleiben, ist eine alternative Lösung für David Rabinowitz, die den tatsächlichen Statuscode verwendet (falls dieser sich nach dem Setzen des Wrappers ändert):

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();
    }

}

Warnung: Viele Annahmen der Klassenhierarchie, wenn Sie hinterlistige Reflexion und Introspektion verwenden, um zu privaten Datenwerten zu gelangen.

0
John Johnson