1.干啥的
首先我们知道setStatus()
方法可以设置请求的状态值,对就是跟在返回头信息第一行HTTP
版本后边的那个数字,如下图 setError()
方法也有这个功能,从它的重载方法来看它来可以带个错误描述的参数
他们都可以改变返回体的状态值
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()
方法处
这是一个权限拦截器中的一个代码,如果没有权限话的进行提示并终止调用,项目中用到了
sitemesh
进行返回页面的封装,所以Response
是被包装过的,但是发现方法进去之后好多都不能打断点,观察Variables
窗口的httpServletResponse
变量可以发现最终调用的Response
对象为org.apache.catalina.connector.ResponseFacade
类,这个类是tomcat-catalina
这个包里的
进入方法
首先判断有没有提交,提交了直接报错 然后调用了
org.apache.catalina.connector.Response
类中的sendError()
方法 注意这个setError()
这个方法 使用cas
方法进行对一个状态值errorState
设置为1 ,正是这状态值让后续的异常处理决定是否再次调用<error-page>
的配置进行处理,再看下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)));
}
}
查下这个方法的调用 进入
StandardHostValve
的status(Request request, Response response)
方法 这个方法上的注释已经说的很清楚了哈,只有在isError()
属性为真才会执行下边的代码,啥时候为真呢,就是调用了sendError()
方法 依次进去看看 再次看到了熟悉的errorState
属性。
在下边的代码中我们还可以看到将statusCode
和message
放入了request
中,名字是啥
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()
方法
使用
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
的源代码看,更方便
今天的文章Response.sendError()和setStatus()方法的区别分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/13756.html