最近在开发项目时,由于前端代码调用后端接口,需要使用响应状体码告知前端登录异常(401)和权限验证不通过(403)。前端拿到对应的状态码会做出相应的处理。
上述的登录验证和权限验证,后端采用Spring拦截器技术实现。为了返回指定的状态码,使用了HttpServletResponse中的setStatus方法。一切都正常运行,没问题!但突然我有了个想法,如果登录验证不通过,需要跳转到专门负责显示401友好提示信息的页面,如何做?有人会说使用sendRedirect方法,可以。还有吗?
我的做法是直接根据响应状态码,依赖web.xml中的error-page配置实现报错页面的跳转。相信下面代码的配置,搞JavaWeb开发的人应该都会熟悉:
```
<error-page>
<error-code>401</error-code>
<location>/WEB-INF/view/401.jsp</location>
</error-page>
```
但在真正运行时发现,setStatus确实可以设置response的状态码,却无法像设想的那样,显示出401.jsp页面中的内容。经过一番搜索查证,发现使用sendError代替setStatus,可以达到期望的效果。可是,为什么?sendError和setStatus有何区别?下面是直译官方API文档的内容:
sendError(int sc):使用指定的状态码并清空缓冲,发送一个错误响应至客户端。如果响应已经被提交,这个方法会抛出IllegalStateException。使用这个方法后,响应则应该被认为已被提交,且不应该再被进行写操作了。
sendError(int sc, String msg):使用指定的状态码发送一个错误响应至客户端。服务器默认会创建一个HTML格式的服务错误页面作为响应结果,其中包含参数msg指定的文本信息,这个HTML页面的内容类型为“text/html”,保留cookies和其他未修改的响应头信息。如果一个对应于传入的错误码的错误页面已经在web.xml中声明,那么这个声明的错误页面将会优先于建议的msg参数服务于客户端。(ps:相比较上面的方法,我更倾向于前者。使用上面的方法,可以通过定制不同状态的响应结果显示于客户端,我们应该想让客户端看到服务器创建出的简单粗暴的页面吧?)
setStatus(int sc):设置响应的状态码。这个方法被用于当响应结果正常时(例如,状态码为SC_OK或SC_MOVED_TEMPORARTLY)设置响应状态码。如果发生错误,而且来访者希望调用在web应用中定义的错误页面作为显示,那么应该使用sendError方法代替之。使用setStatus方法之后,容器会清空缓冲并设置Location响应头,保留cookies和其他响应头信息。
从直译的结果不难发现哈,sendError适用于报错且存在对应的报错页面配置作为输出显示的情况,而setStatus适用于正常响应的情况,仅仅可以改变响应状态码而已。