美文网首页
Response.sendError()和setStatus()

Response.sendError()和setStatus()

作者: 马木木 | 来源:发表于2020-08-08 17:42 被阅读0次

1.干啥的

首先我们知道setStatus()方法可以设置请求的状态值,对就是跟在返回头信息第一行HTTP版本后边的那个数字,如下图

image
sendError()方法也有这个功能,从它的重载方法来看它来可以带个错误描述的参数
image

他们都可以改变返回体的状态值

2.不同处

先说结果sendError()的状态值可以在web.xml中配置的<error-page></error-page>再次处理一遍,比如返回特定的友好的错误提示页面或者是返回具体的错误返回内容都是可以的,我觉得这个主要是对返回的body内容进行填充,当然在此也是可以改变状态码的,下边会说到。
<error-page>标签如下

<error-page>
        <error-code>401</error-code>
        <location>/noPermissionError.htm</location>
</error-page>

这里的意思是如果状态码是401的话,会再次请求/noPermissionError.htm这个请求,在此期间可以对返回内容再次调整。除了状态码外,还可以对具体的异常类型进行处理,这里就不解释了

3.为啥sendError()可以有特权

从代码层次来debug一下
首先我们来到sendError()方法处

image

这是一个权限拦截器中的一个代码,如果没有权限话的进行提示并终止调用,项目中用到了sitemesh进行返回页面的封装,所以Response是被包装过的,但是发现方法进去之后好多都不能打断点,观察Variables窗口的httpServletResponse变量可以发现最终调用的Response对象为
org.apache.catalina.connector.ResponseFacade类,这个类是tomcat-catalina这个包里的

image

进入方法


image

首先判断有没有提交,提交了直接报错
然后调用了org.apache.catalina.connector.Response类中的sendError()方法

image
注意这个sendError()这个方法
image
使用cas方法进行对一个状态值errorState设置为1 ,正是这状态值让后续的异常处理决定是否再次调用<error-page>的配置进行处理,再看下setStatus()方法一目了然
image

4.再进一步

<error-page>标签如何被解析

进入catalina包的WebXml类的configureContext()我们猜测(为啥子是猜测,因为我就是猜的哈)这个就是tomcat解析web.xml的类,然后可以进入StandardContext类的addErrorPage()方法,如下

@Override
    public void addErrorPage(ErrorPage errorPage) {
        // Validate the input parameters
        if (errorPage == null)
            throw new IllegalArgumentException
                (sm.getString("standardContext.errorPage.required"));
        String location = errorPage.getLocation();
        if ((location != null) && !location.startsWith("/")) {
            if (isServlet22()) {
                if(log.isDebugEnabled())
                    log.debug(sm.getString("standardContext.errorPage.warning",
                                 location));
                errorPage.setLocation("/" + location);
            } else {
                throw new IllegalArgumentException
                    (sm.getString("standardContext.errorPage.error",
                                  location));
            }
        }

        // Add the specified error page to our internal collections
        String exceptionType = errorPage.getExceptionType();
        if (exceptionType != null) {
            synchronized (exceptionPages) {
                exceptionPages.put(exceptionType, errorPage);
            }
        } else {
            synchronized (statusPages) {
                if (errorPage.getErrorCode() == 200) {
                    this.okErrorPage = errorPage;
                }
                statusPages.put(Integer.valueOf(errorPage.getErrorCode()),
                                errorPage);
            }
        }
        fireContainerEvent("addErrorPage", errorPage);

    }

可以清楚的看到根据异常和状态值的异常处理的整理,再猜一下,搜一下对这个statusPages的调用

就它了也是在StandardContext

@Override
    public ErrorPage findErrorPage(int errorCode) {
        if (errorCode == 200) {
            return (okErrorPage);
        } else {
            return (statusPages.get(Integer.valueOf(errorCode)));
        }

    }

查下这个方法的调用 进入StandardHostValvestatus(Request request, Response response)方法

image
这个方法上的注释已经说的很清楚了哈,只有在isError()属性为真才会执行下边的代码,啥时候为真呢,就是调用了sendError()方法
依次进去看看
image
image
再次看到了熟悉的errorState属性。

在下边的代码中我们还可以看到将statusCodemessage放入了request中,名字是啥

image
public static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
public static final String ERROR_MESSAGE = "javax.servlet.error.message";

所以在之后的异常处理时如果想获得sendError()时的参数,可以get这俩个属性得到

request.getAttribute("javax.servlet.error.status_code")
request.getAttribute("javax.servlet.error.message")

找到对应的异常处理配置之后,进入custom()方法

image

使用RequestDispatcher对象forward到配置的<location>继续对结果进行包装,这个<location>最终可以是个页面跳转,也可以是json字符串
如下

@RequestMapping("error.htm")
    public String error() {
        return "error.ftl";
    }
@RequestMapping(value = "noPermissionError.htm", produces = {"application/json;charset=UTF-8"})
    @ResponseBody
    public Map<String, Object> noPermissionError(HttpServletRequest request) {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("status", request.getAttribute("javax.servlet.error.status_code"));
        map.put("reason", request.getAttribute("javax.servlet.error.message"));
        return map;
    }

这边其实也可以改变状态码,可以使用@ResponseStatus注解,比如

 @RequestMapping(value = "noPermissionError.htm", produces = {"application/json;charset=UTF-8"})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Map<String, Object> noPermissionError(HttpServletRequest request) {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("status", request.getAttribute("javax.servlet.error.status_code"));
        map.put("reason", request.getAttribute("javax.servlet.error.message"));
        return map;
    }

这个状态码最后就是200,可以添加自己的业务错误码进行业务判断

附录

想在项目中跟踪到tomcat的类时需要在项目中添加依赖

<dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>7.0.86</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-coyote</artifactId>
            <version>7.0.86</version>
            <scope>provided</scope>
        </dependency>

作用域一定要是provided,否则启动时会冲突,但是调试的时候发现还是有一些类不知道需要引入哪些包会缺失,大家可以到apache官网下载tomcat的源代码看,更方便

下载地址
http://tomcat.apache.org/download-60.cgi

相关文章

  • Response.sendError()和setStatus()

    1.干啥的 首先我们知道setStatus()方法可以设置请求的状态值,对就是跟在返回头信息第一行HTTP版本后边...

  • Web核心day04-Cookie&Session

    一.请求转发和重定向 重定向早期写法: response.setStatus(302); // respon...

  • cookie&session

    响应首行setstatus(int)sendError(int,String)响应头setHeaderaddHea...

  • 请求响应与会话相关内容

    一、HttpServletResponse对象 1、发送状态码相关的方法 setStatus() 设置响应状态码,...

  • 使用RouterDelegate时遇到的问题

    因为RouterDelegate不是widget,所以无法直接调用setStatus触发build方法,通过wit...

  • Servlet HTTP 常见状态码总结

    Servlet HTTP 状态码总结 确保在使用 PrintWriter 实际返回任何内容之前调用 setStatus。

  • Response重定向

    重定向 使用步骤:1、设置状态码为302 setStatus()2、设置响应头location setHeade...

  • response

    功能:设置响应消息 设置响应行1.格式HTTP/1.1 200 ok,设置状态码:setStatus(int sc...

  • -和 和 -

    产品介绍:和和是一款会员制共享平台;所有 经营者可在APP内注册和和商家成为会员供 应商(实体店、网店、微商、平台...

  • &和&&,|和||

    原文:https://blog.csdn.net/chinabestchina/article/details/7...

网友评论

      本文标题:Response.sendError()和setStatus()

      本文链接:https://www.haomeiwen.com/subject/zabhdktx.html