springboot⾃定义http反馈状态码
最近在开发⼀些http server类型程序,通过spring boot构建⼀些web程序,这些web程序之间通过http进⾏数据访问、共享,如下图:
假设现在client发起⼀次保存数据的请求到server,server可能会返回如下类似的数据:
{
"status":1,
"message":"xxxxxx"
}
然后client通过解析json获得status来判断当前的请求操作是否成功,开发过程中通过都是这么做的,但是这样在restful设计中不怎么好,其实这个status字段的表达完全可以通过http status来表⽰,类似404、500、502这种都有明确的定义并且相互理解、沟通起来也⽅便。
⽂章主要记录⼀下我是如何在spring boot中实现⾃定反馈状态码的,以及我到的三种实现⽅式。
第⼀种,使⽤@ResponseStatus
这是⼀个注解,可以作⽤在⽅法和类上⾯,如下使⽤:
在⽅法上使⽤⽅式:
1 @RequestMapping(value = "/user", method = RequestMethod.GET)
2 @ResponseStatus(code=HttpStatus.INTERNAL_SERVER_ERROR,reason="server error")
3public String getUser(){
4return "im zhangsan";
5 }
启动web程序,通过postman访问127.0.0.1:8100/user,会出现下⾯结果:
{
"timestamp": 1497850427325,
"status": 500,
"error": "Internal Server Error",
"message": "server error",
hello spring是什么意思"path": "/user"
}
这⾥我⼀开始觉得很奇怪,为什么我的getUser⽅法中没有错误,结果还是出现了500错误?原因就是@ResponseStatus注解的问题,我后⾯猜测它会强制的将映射转化成500的状态码。这种应⽤场景我想不太明⽩在什么地⽅会⽤到。
在类中使⽤⽅式:
1 @ResponseStatus(code=HttpStatus.INTERNAL_SERVER_ERROR,reason="111")
2public class ServerException extends Exception {
3
4 }
这种使⽤⽅式就是将⾃定义异常和状态码结合在⼀起,合理使⽤⾃定义异常机制可以最⼤化的提⾼程序的健壮性,下⾯看如何使⽤:
1 @RequestMapping(value = "/user", method = RequestMethod.GET)
2public String getUser(@RequestParam String userName) throws ServerException{
3if(StringUtils.isEmpty(userName)){
4throw new ServerException();
5 }
6return "im zhangsan";
7 }
这段代码的意思是当userName字段为null的时候会抛出ServerException异常,但是ServerException类被标记了@ResponseStatus注解,因此会直接报500错误,如果觉得500不适合还可以定义其它的错误代码。
这种⽅式看着已经很好了,可以按照逻辑⾃定义反馈码,程序够健壮。这种⽅式也有不好地⽅,如果反馈码太多需要定义太多的异常类,并且错误内容reason还是不能⼿动定义。
到这⾥,我基本上放弃了@ResponseStatus的使⽤了。
第⼆种,使⽤HttpServletResponse
HttpServletResponse是javax.servlet下的⼀个接⼝,如下使⽤:
1 @RequestMapping(value = "/user", method = RequestMethod.GET)
2public void getUser(HttpServletResponse response) throws IOException{
3 response.setStatus(500);
4 Writer().append("server error");
5 }
这种⽅式可以很好的实现同时满⾜⾃定义反馈码+消息内容,⼀般的实现⽅式也都是这样。但是这样也不是太好,
1. 在括号内创建了⼀个response内置变量,这样显得不够美观,反⽽有些多余。
2. 在⽅法中调⽤了源⽣的⽅法来设置反馈码和消息体,并且如果需要返回json格式数据还需要设置
response.setContentType("application/json");和response.setCharacterEncoding("UTF-8");,这样做有些多余,重复的⼯作太多,虽然可以进⾏封装。
3. 最严重的问题这个⽅法必须是void类型,否则就会和@ResponseBody出现冲突,其次就是不能利⽤@ResponseBody⾃动封装json的
特性,在spring mvc框架中如果在⽅法上加上@ResponseBody是可以对返回值⾃动进⾏json封装的。
再其他的,如果没有到,估计也只能接受这个不完美的东西了。
后来在翻阅⽂档的时候到了ResponseEntity这么⼀个东西,这就是我要说的第三种⽅式。
第三种,使⽤ResponseEntity
不多说,直接上代码:
1 @RequestMapping(value = "/user", method = RequestMethod.GET)
2public ResponseEntity<Map<String,Object>> getUser() throws IOException{
3 Map<String,Object> map = new HashMap<String,Object>();
4 map.put("name", "zhangsan");
5return new ResponseEntity<Map<String,Object>>(map,HttpStatus.OK);
6 }
通过postman查看返回结果,如下:
{
"name": "zhangsan"
}
可以直接将map对象帮我转化成json对象,并且可以获得⾃定义状态码,很好,很强⼤。
这种⽅式很和我意,
1. 不需要多于的HttpServletResponse,看着很⼲净。
2. 可以充分利⽤@ResponseBody注解,直接将我的返回值帮我转化成json对象。
3. 在设置返回值的时候同时还可以设置http反馈码,HttpStatus是springframework提供的⼀个枚举类,⾥⾯封装了所有的http反馈码,⽅
便使⽤命名统⼀,不会有任何歧义。
相⽐于前⾯两种,这种⽅式很对我胃⼝。
仔细看了ResponseEntity的说明,发现spring mvc其它很多地⽅也都有使⽤,如下,下⾯内容摘⾃org.springframework.http.ResponseEntity ⽂件注释,
In RestTemplate, this class is returned by getForEntity() and exchange():
1 ResponseEntity<String> entity = ForEntity("example", String.class);
2 String body = Body();
3 MediaType contentType = Headers().getContentType();
4 HttpStatus statusCode = StatusCode();
Can also be used in Spring MVC, as the return value from a @Controller method:
1 @RequestMapping("/handle")
2public ResponseEntity<String> handle() {
3 URI location = ...;
4 HttpHeaders responseHeaders = new HttpHeaders();
5 responseHeaders.setLocation(location);
6 responseHeaders.set("MyResponseHeader", "MyValue");
7return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
8 }
这就是上⾯说过的。
Or, by using a builder accessible via static methods:
1 @RequestMapping("/handle")
2public ResponseEntity<String> handle() {
3 URI location = ...;
ated(location).header("MyResponseHeader", "MyValue").body("Hello World");
5 }
⾃定义http反馈码在设计优良的restful api中起到关键作⽤,http反馈码是业内统⼀、共识的,建议在尽量不要通过解析json来获得status判断操作结果。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论