Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何从ServletFilter中的ServletResponse中获取HTTP状态代码?_Java_Servlets_Servlet Filters_Http Status Codes - Fatal编程技术网

Java 如何从ServletFilter中的ServletResponse中获取HTTP状态代码?

Java 如何从ServletFilter中的ServletResponse中获取HTTP状态代码?,java,servlets,servlet-filters,http-status-codes,Java,Servlets,Servlet Filters,Http Status Codes,我正在尝试报告从我的webapp返回的每个HTTP状态代码。但是,状态代码似乎无法通过ServletResponse访问,或者即使我将其转换为HttpServletResponse。是否有办法在ServletFilter中访问此值?编写一个HttpServletResponseWrapper并重写所有setStatus()、sendError()和sendRedirect()方法以记录所有内容。编写一个过滤器,在每次请求时为响应对象交换包装器。首先,您需要将状态代码保存在一个可访问的位置。最好将

我正在尝试报告从我的webapp返回的每个HTTP状态代码。但是,状态代码似乎无法通过ServletResponse访问,或者即使我将其转换为HttpServletResponse。是否有办法在ServletFilter中访问此值?

编写一个HttpServletResponseWrapper并重写所有setStatus()、sendError()和sendRedirect()方法以记录所有内容。编写一个过滤器,在每次请求时为响应对象交换包装器。

首先,您需要将状态代码保存在一个可访问的位置。最好将响应与您的实现打包并保存在一起:

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

}
为了使用此包装器,您需要添加一个servlet过滤器,前提是您可以进行报告:

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
    }

}

上面David的回答中缺少的一点是,您还应该覆盖另一种形式的sendError:

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

自Servlet3.0以来,有一个

因此,如果有升级的空间,可以升级到Servlet3.0(Tomcat7、GlassFish3、JBossAS6等),而不需要包装器

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

还需要包含#sendRedirect的包装,最好将状态初始化为“200”而不是“0”

private int httpStatus = SC_OK;

...

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

如果您使用的是较旧的容器,那么David Rabinowitz的另一个解决方案是使用实际状态代码(如果在使用包装器设置后发生更改):

公共类StatusExposingServletResponse扩展了HttpServletResponseWrapper{
公共状态ExposingServletResponse(HttpServletResponse){
超级(响应);
}
@凌驾
公共void发送错误(int sc)引发IOException{
超级发送错误(sc);
}
@凌驾
public void sendError(int sc,String msg)引发IOException{
超级发送错误(sc,msg);
}
@凌驾
公共状态(内部sc){
super.setStatus(sc);
}
public int getStatus(){
试一试{
ServletResponse对象=super.getResponse();
//调用私有方法“getResponse”
方法method1=object.getClass().getMethod(“getResponse”);
Object servletResponse=method1.invoke(对象,新对象[]{});
//调用父级私有方法“getResponse”
方法method2=servletResponse.getClass().getMethod(“getResponse”);
objectparentresponse=method2.invoke(servletResponse,新对象[]{});
//调用父级私有方法“getResponse”
方法method3=parentResponse.getClass().getMethod(“getStatus”);
int-httpStatus=(整数)method3.invoke(parentResponse,新对象[]{});
返回httpStatus;
}
捕获(例外e){
e、 printStackTrace();
返回HttpServletResponse.SC\u已接受;
}
}
公共字符串getMessage(){
试一试{
ServletResponse对象=super.getResponse();
//调用私有方法“getResponse”
方法method1=object.getClass().getMethod(“getResponse”);
Object servletResponse=method1.invoke(对象,新对象[]{});
//调用父级私有方法“getResponse”
方法method2=servletResponse.getClass().getMethod(“getResponse”);
objectparentresponse=method2.invoke(servletResponse,新对象[]{});
//调用父级私有方法“getResponse”
方法method3=parentResponse.getClass().getMethod(“getReason”);
字符串httpStatusMessage=(字符串)method3.invoke(parentResponse,新对象[]{});
如果(httpStatusMessage==null){
int status=getStatus();
java.lang.reflect.Field[]fields=HttpServletResponse.class.getFields();
for(java.lang.reflect.Field:fields){
if(status==field.getInt(servletResponse)){
httpStatusMessage=field.getName();
httpStatusMessage=httpStatusMessage.replace(“SC_”)和;
如果(!“OK.”等于(httpStatusMessage)){
httpStatusMessage=httpStatusMessage.toLowerCase();
httpStatusMessage=httpStatusMessage.replace(““,”);
httpStatusMessage=大写字母(httpStatusMessage);
}
打破
}
}
}
返回httpStatusMessage;
}
捕获(例外e){
e、 printStackTrace();
返回“”;
}
}
专用静态字符串大写字母(字符串s){
对于(int i=0;i

警告:当使用秘密反射和内省来获取私有数据值时,会对类层次结构进行大量假设。

除了David的答案之外,您还需要覆盖重置方法:

@Override
public void reset() {
    super.reset();
    this.httpStatus = SC_OK;
}
。。。以及不推荐使用的setStatus(int,String)


谢谢William,我已经将它添加到了我的示例中。如果有人在页面结束前没有阅读,请注意Joel下面的评论,将默认状态设置为200,并覆盖sendRedirect(..),这对Servlet上的旧版本Tomcat非常有帮助
@Override
public void reset() {
    super.reset();
    this.httpStatus = SC_OK;
}
@Override
public void setStatus(int status, String string) {
    super.setStatus(status, string);
    this.httpStatus = status;
}