Spring Boot提供RESTful接口时的错误处理实践
本文首发于个人网站:http://www.javaadu.online/,如需转载,请注明出处
使用Spring Boot开发微服务的过程中,我们会使用别人提供的接口,也会设计接口给别人使用,这时候微服务应用之间的协作就需要有一定的规范。
基于rpc协议,我们一般有两种思路:(1)提供服务的应用统一将异常包起来,然后用错误码交互;(2)提供服务的应用将运行时异常抛出,抛出自定义的业务异常,服务的调用者通过异常catch来处理异常情况。
基于HTTP协议,那么最流行的就是RESTful协议,服务提供方会自己处理所有异常,并且返回的结果中会跟HTTP的状态码相结合,这篇文章我们就用一个例子来说明RESTful接口的错误处理如何做。
首先我们需要新建一个简单的Controller,代码如下:
@RestController
class GreetingController {
@RequestMapping("/greet")
String sayHello(@RequestParam("name") String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("The 'name' parameter must not be null or empty");
}
return String.format("Hello %s!", name);
}
}
通过http请求客户端——httpie发送HTTP请求,这个工具比curl的好处是:返回值信息有语法高亮、对返回的JSON字符串自动格式化。启动服务器,使用命令http http://127.0.0.1:8080/greet?name=duqi发起请求,结果如下:
HTTP/1.1 200 OK
Content-Length: 11
Content-Type: text/plain;charset=UTF-8
Date: Sat, 05 Dec 2015 05:45:03 GMT
Server: Apache-Coyote/1.1
X-Application-Context: application
现在我们制造一个错误的请求,@RequestParam是获取URL中的参数,如果这个参数不提供则会出错。因此,我们发送一个命令http http://127.0.0.1:8080,看结果如何。
HTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 05:54:06 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application
{
"error": "Bad Request",
"exception": "org.springframework.web.bind.MissingServletRequestParameterException",
"message": "Required String parameter 'name' is not present",
"path": "/greet",
"status": 400,
"timestamp": 1449294846060
}
可以看到,由于没有提供name参数,服务器返回的状态码是400:错误的请求。在响应体中的内容依次如下:
- error : 错误信息;
- exception:异常的类型,MissingServletRequestParameterExeption,见名知意,说明是缺少了某个请求参数;
- message:对异常的说明
- path:显示请求的URL路径;
- status:表示返回的错误码
- timestamp:错误发生的时间戳,调用System.currentMills()
如果我们给定name参数,却不给它赋值,又会如何?发送命令http http:127.0.0.1:8080/greet?name,则服务器的返回值如下:
HTTP/1.1 500 Internal Server Error
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 06:01:24 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application
{
"error": "Internal Server Error",
"exception": "java.lang.IllegalArgumentException",
"message": "The 'name' parameter must not be null or empty",
"path": "/greet",
"status": 500,
"timestamp": 1449295284160
}
对比上面,可以看出,这次返回的错误码是500,表示服务器内部错误;返回的异常类型是java.lang.IllegalArgumentException,表示参数不合法。服务器内部错误表示服务器抛出了异常缺没有处理,我们更愿意API返回400,告诉调用者自己哪里做错了。如何实现呢?利用@ExceptionHandler注解即可。
在GreetingController控制器中加入如下处理函数,用于捕获这个控制器的异常。
@ExceptionHandler
void handleIllegalArgumentException(IllegalArgumentException e,
HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value());
}
再次发送命令http http:127.0.0.1:8080/greet?name,则返回下面的结果:
HTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 06:08:50 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application
{
"error": "Bad Request",
"exception": "java.lang.IllegalArgumentException",
"message": "The 'name' parameter must not be null or empty",
"path": "/greet",
"status": 400,
"timestamp": 1449295729978
}
说明我们在服务器端捕获了IllegalArgumentException这个异常,并设置response的返回码为400。如果你想对多个异常都进行一样的处理,则上述异常处理代码可以修改为下面这样(给@ExceptionHandler传入参数):
@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
void handleIllegalArgumentException(HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value());
}
现在这个异常处理代码是加在当前的这个控制器中,因此它只处理属于这个控制器的响应,如果我们新建一个类,并用注解@ControllerAdvice修饰,并在这个类中定义上述的异常处理代码,则它会负责处理所有的请求。
Spring Boot 1.2.0以后,还支持在response修改对应的message,只要将对应的message信息传入sendError函数即可,例如:
@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
void handleIllegalArgumentException(HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value(),
"Please try again and with a non empty string as 'name'");
}
再次执行同样的命令,会收到下列反馈:
HTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 06:21:05 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application
{
"error": "Bad Request",
"exception": "java.lang.IllegalArgumentException",
"message": "Please try again and with a non empty string as 'name'",
"path": "/greet",
"status": 400,
"timestamp": 1449296465060
}
如果希望验证请求的参数,可以使用JSR-303 Bean Validation API,并参考Spring Validation。在spring.io上还有一个验证表单输入的例子Validating Form Input。
参考资料
Spring Boot 1.x系列
- Spring Boot的自动配置、Command-line-Runner
- 了解Spring Boot的自动配置
- Spring Boot的@PropertySource注解在整合Redis中的使用
- Spring Boot项目中如何定制HTTP消息转换器
- Spring Boot整合Mongodb提供Restful接口
- Spring中bean的scope
- Spring Boot项目中使用事件派发器模式
本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

Spring Boot提供RESTful接口时的错误处理实践的更多相关文章
- spring boot https --restful接口篇
我们写的接口默认都是http形式的,不过我们的接口很容易被人抓包,而且一抓全是明文的挺尴尬的 spring boot配置https生成证书大的方向有3种: 1.利用keytool自己生成证书 2.从免 ...
- 聊一聊 Spring Boot 中 RESTful 接口设计规范
在设计接口时,有很多因素要考虑,如接口的业务定位,接口的安全性,接口的可扩展性.接口的稳定性.接口的跨域性.接口的协议规则.接口的路径规则.接口单一原则.接口过滤和接口组合等诸多因素,本篇文章将简要分 ...
- 无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范
在设计接口时,有很多因素要考虑,如接口的业务定位,接口的安全性,接口的可扩展性.接口的稳定性.接口的跨域性.接口的协议规则.接口的路径规则.接口单一原则.接口过滤和接口组合等诸多因素,本篇文章将简要分 ...
- 通过spring boot提供restful api
1 将返回设置为produces = "application/json" 返回给客户端json格式的response. 2 对各种异常的处理 各种异常如何返回给客户端? 各种异常 ...
- 使用Spring Boot操作Hive JDBC时,启动时报出错误:NoSuchMethodError: org.eclipse.jetty.servlet.ServletMapping.setDef
使用Spring Boot操作Hive JDBC时,启动时报出错误:NoSuchMethodError: org.eclipse.jetty.servlet.ServletMapping.setDef ...
- Spring Boot提供的特性
一.导览 本文主要按以下模块介绍spring Boot(1.3.6.RELEASE)提供的特性. SpringApplication类 外部化配置 Profiles 日志 开发WEB应用 Securi ...
- Spring Boot2 系列教程(三十一)Spring Boot 构建 RESTful 风格应用
RESTful ,到现在相信已经没人不知道这个东西了吧!关于 RESTful 的概念,我这里就不做过多介绍了,传统的 Struts 对 RESTful 支持不够友好 ,但是 SpringMVC 对于 ...
- Spring Boot构建 RESTful 风格应用
Spring Boot构建 RESTful 风格应用 1.Spring Boot构建 RESTful 风格应用 1.1 实战 1.1.1 创建工程 1.1.2 构建实体类 1.1.4 查询定制 1.1 ...
- spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获
spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获 当你的某个控制器内的某个方法报错,基本上回显示出java错误代码,非常不友好,这 ...
随机推荐
- Docker学习之docker常用命令
docker ps -a 表示所有容器 docker pull 获取image docker build 创建image docker run 运行container docker images 列出 ...
- Java基本数据类型转换及运算符
上次我们说到完了Java中的基本数据类型,今天我们来说说Java中的基本数据类型转换和Java中的运算符 基本数据类型转换 java中可以从任意基本数据类型转型到外的基本数据类型 注意:(boolea ...
- 在wxml中直接写js代码(wxs)
我们在h5开发中,很多时候要在html中写到js代码,这个很容易实现.但是在微信小程序开发中,是不能直接在wxml中写js代码的,因此就有了wxs.在wxml中用wxs代码,有以下几种方式(在小程序文 ...
- BeanFactory not initialized or already closed
产生这个错误有两个可能, 一.你没有配置初始化文件,在web.xml中配置如下 <context-param> <param-name>contextConfigLocatio ...
- Spring Boot (五): Redis缓存使用姿势盘点
1. Redis 简介 Redis 是目前业界使用最广泛的内存数据存储.相比 Memcached,Redis 支持更丰富的数据结构,例如 hashes, lists, sets 等,同时支持数据持久化 ...
- Redis数据库之编程项目及练习资源
实训项目 : NOSQL数据库设计与应用实训 注释: Redis数据库编程项目示例及练习资源 项目源码获取: https://pan.baidu.com/s/19f0F7cmx ...
- JVM 调优 - jhat
Java命令学习系列(五)——jhat 2016-01-21 分类:Java 阅读(8708) 评论(3) 阿里大牛珍藏架构资料,点击链接免费获取 jhat(Java Heap Analysis To ...
- 浏览器端获取短信验证码java实现——阿里云短信服务
需求:浏览器端输入手机号,获取验证码.点击登录,验证验证码是否输入错误.是否超时等情况,一旦校验通过,将用户数据保存到数据中(业务逻辑). 前提:注册阿里用户,开通短信服务,申请key.秘钥.签名.短 ...
- Python简单的抓取静态网页内容
import requests from bs4 import BeautifulSoup res = requests.get('http://news.sina.com.cn/china/')#获 ...
- bootstrap具体知识点(2)
3.以移动设备为优先 <meta name=”viewport” content=”width=device-width,initial-scale=1,user-scalable=no”> ...