Response.sendError()和setStatus()方法的区别

Response.sendError()和setStatus()方法的区别先说结果setError()的状态值可以在web.xml中配置的<error-page</error-page再次处理一遍,比如返回特定的友好的错误提示页面或者是返回具体的错误返回内容都是可以的,我觉得这个主要是对返回的body内容进行填充,当然在此也是…

1.干啥的

首先我们知道setStatus()方法可以设置请求的状态值,对就是跟在返回头信息第一行HTTP版本后边的那个数字,如下图 Response.sendError()和setStatus()方法的区别 setError()方法也有这个功能,从它的重载方法来看它来可以带个错误描述的参数 Response.sendError()和setStatus()方法的区别

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

2.不同处

先说结果setError()的状态值可以在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.为啥setError()可以有特权

从代码层次来debug一下 首先我们来到setError()方法处 Response.sendError()和setStatus()方法的区别

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

进入方法 Response.sendError()和setStatus()方法的区别

首先判断有没有提交,提交了直接报错 然后调用了org.apache.catalina.connector.Response类中的sendError()方法 Response.sendError()和setStatus()方法的区别 注意这个setError()这个方法 Response.sendError()和setStatus()方法的区别 使用cas方法进行对一个状态值errorState设置为1 ,正是这状态值让后续的异常处理决定是否再次调用<error-page>的配置进行处理,再看下setStatus()方法一目了然 Response.sendError()和setStatus()方法的区别

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)方法 Response.sendError()和setStatus()方法的区别 这个方法上的注释已经说的很清楚了哈,只有在isError()属性为真才会执行下边的代码,啥时候为真呢,就是调用了sendError()方法 依次进去看看 Response.sendError()和setStatus()方法的区别 Response.sendError()和setStatus()方法的区别 再次看到了熟悉的errorState属性。

在下边的代码中我们还可以看到将statusCodemessage放入了request中,名字是啥 Response.sendError()和setStatus()方法的区别

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()方法 Response.sendError()和setStatus()方法的区别

使用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的源代码看,更方便

下载地址 tomcat.apache.org/download-60…

今天的文章Response.sendError()和setStatus()方法的区别分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/13756.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注