Spring Boot Error Response_weixin_34150224的博客-程序员秘密

技术标签: java  json  

本文翻译自:Spring Boot Error Responses

在昨天的文章最后,我提到一个问题,就是我的例子对错误处理的设计不够。按照RESTful的设计,既然请求是借助HTTP的方法,那么返回信息也应该借助HTTP的状态码和其他信息。经过查找资料,决定将这篇文章中提到的例子实践一次,并用我的话总结下。

首先我们需要新建一个简单的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

参考资料

  1. 模拟GET/POST请求的工具
  2. Spring Boot Error Response

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34150224/article/details/90628749

智能推荐

嵌入式学习:stm32学习路线推荐之思维导图_stm32学习思维导图_昧着良心说实话的博客-程序员秘密

从9月1日开始学习STM32后,对于STM32的一些个人总结:1.对于STM32和51的区别:对于 STM32来说,基本的大概都和51单片的内容相似,但是由于STM的引脚和寄存器的数量较多,所以需要一个更加完善的管理机制,导致了—时钟 的产生。2.对于STM32来说,一般文件都是分为3个部分组成的(正点原子版):1. .C文件 2. 。H文件 3.main函数 其中.c文件...

wx.getUserInfo获取不到用户信息_超小盆友的媳妇儿的博客-程序员秘密

今日份白痴在线,wx.getUserInfo就是取不到用户信息,官网说得授权,然后出来了,附上一点代码:

laravel框架中使用GuzzleHttp并发请求多个接口_guzzlehttp 并发访问不同的地址_铮亮不锈的博客-程序员秘密

Guzzle是一个PHP的HTTP客户端,用来轻而易举地发送请求,并集成到我们的WEB服务上。接口简单:构建查询语句、POST请求、分流上传下载大文件、使用HTTP cookies、上传JSON数据等等。发送同步或异步的请求均使用相同的接口。 使用PSR-7接口来请求、响应、分流,允许你使用其他兼容的PSR-7类库与Guzzle共同开发。抽象了底层的HTTP传输,允许你改变环境以及其他的代码,如:对cURL与PHP的流或socket并非重度依赖,非阻塞事件循环。中间件系统允许你创建构成客户端行为。

hdoj Super Jumping! Jumping! Jumping! 1087 (DP求单调递增最大值)_没有能与不能只有想与不想的博客-程序员秘密

Super Jumping! Jumping! Jumping!Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 30877    Accepted Submission(s): 13826Problem Descript

拖拽改变DataGridView的行顺序_datagridview调整行顺序_数据之道的博客-程序员秘密

DataGridView并没有属性可以设置改变行顺序,需要做如下操作,假设改变dataGridView2的行顺序,定义全局变量记录最后一次选中的行号:int selectionIdx = 0;在DragEnter事件中添加如下代码:private void dataGridView2_DragEnter(object sender, DragEventArgs e){   ...

怎么在github上创建文件夹_lovewingss的博客-程序员秘密

直接在网页版创建一个新项目,然后在项目里面创建文件就可以的。下周github for windows客户端,然后登陆,选择一个目录和github网页版的同步,在这个文件夹下直接建立文件,就相当于在github根目录下建立文件夹。确认本地安装git服务,然后找一个目录,当作github和本地电脑的同步目录,然后可以选择sourcetree等git管理工具或者,git命令行,g

随便推点

torch.view函数用法_九磅十五便士丶的博客-程序员秘密

这句话一般出现在model类的forward函数中,具体位置一般都是在调用分类器之前。分类器是一个简单的nn.Linear()结构,输入输出都是维度为一的值,x=x.view(x.size(0),-1)这句话的出现就是为了将前面多维度的tensor展平成一维。view中一个参数定为-1,代表自动调整这个维度上的元素个数,以保证元素的总数不变。在使用pytorch定义神经网络时,经常会看到类似如下的.view()用法。view()相当于reshape、resize,重新调整Tensor的形状。........

Java中Jaxb的使用_java jaxb_Himma_DH的博客-程序员秘密

最近工作对接接口出入参均是Xml,因此使用了jaxb来处理首先先添加依赖:<!--jaxb--><dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.2.5</version></dependency><dependency>

npm install -g n 报错 Windows_window npn -g n_衣乌安、的博客-程序员秘密

是不是像我一样呢?~~恭喜你!我也很无奈!windows不支持 n ,下面是从 n 的github中截的图,看来他需要贡献。。那怎么办呢?换个版本管理器吧nvm-windows:  https://github.com/coreybutler/nvm-windows...

python官网的软件-mPython_编程大乐趣的博客-程序员秘密

mPython官方版是款针对程序员们所打造的图形编程工具。mPython电脑版支持命令式程序设置,并具有强大的编程库,用户可将其与多种模块完美相结合在一起。mPython还可以支持函数,仿真、hex、python、blockly三种代码读写等功能。并可以与TPYBoard系类开发板配合使用,直接连接PC端进行编程。相似软件版本说明软件地址2012 官方版查看1.0.3 官方版查看2.4.530.1...

弹出层layer的使用心得_老贼大魔王的博客-程序员秘密

今天写一个弹出层插件layer的使用心得,推荐仔细阅读官方API。主要是说明如何在弹出的页面里改变title。1.先附上主页面的代码:<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><% String path=request.getContextPath()

Bitmap与Matrix旋转ImageView_风不清云不淡的博客-程序员秘密

<br />例说明<br />先前曾看过ImageView Widget的展示,虽可以将许多ImageView层层叠叠放在一起,再控制ImageView的图片来模拟动画的效果,但ImageView默认是没办法旋转的,那么要如何让ImageView产生旋转的效果呢?<br />要旋转ImageView其实很简单,先将前一次ImageView里的图片放入暂存Bitmap,接着再利用Bitmap.createBitmap来创建新的Bitmap对象,在创建新的Bitmap对象的同时,搭配Matrix对象里的setR

推荐文章

热门文章

相关标签