SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势

这篇具有很好参考价值的文章主要介绍了SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

虽然 http 的提供了一整套完整、定义明确的状态码,但实际的业务支持中,后端并不总会遵守这套规则,更多的是在返回结果中,加一个 code 字段来自定义业务状态,即便是后端 5xx 了,返回给前端的 http code 依然是 200

那么如果我想遵守 http 的规范,不同的 case 返回不同的 http code 在 Spring 中可以做呢?

本文将介绍四种设置返回的 HTTP CODE 的方式

  • @ResponseStatus 注解方式

  • HttpServletResponse#sendError

  • HttpServletResponse#setStatus

  • ResponseEntity

I. 返回 Http Code 的 n 种姿势

0. 环境

进入正文之前,先创建一个 SpringBoot 项目,本文示例所有版本为 spring-boot.2.1.2.RELEASE

(需要测试的小伙伴,本机创建一个 maven 项目,在pom.xml文件中,拷贝下面的配置即可)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/><!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot-local</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

下面所有的方法都放在 ErrorCodeRest 这个类中

@RestController
@RequestMapping(path = "code")
publicclass ErrorCodeRest {
}

1. ResponseStatus 使用姿势

通过注解@ResponseStatus,来指定返回的 http code, 一般来说,使用它有两种姿势,一个是直接加在方法上,一个是加在异常类上

a. 装饰方法

直接在方法上添加注解,并制定对应的 code

/**
 * 注解方式,只支持标准http状态码
 *
 * @return
 */
@GetMapping("ano")
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "请求参数异常!")
public String ano() {
    return"{\"code\": 400, \"msg\": \"bad request!\"}";
}

实测一下,返回结果如下

➜  ~ curl 'http://127.0.0.1:8080/code/ano' -i
HTTP/1.1 400
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Jan 2020 01:29:04 GMT
Connection: close

{"timestamp":"2020-01-05T01:29:04.673+0000","status":400,"error":"Bad Request","message":"请求参数异常!","path":"/code/ano"}%

当我们发起请求时,返回的状态码为 400,返回的数据为 springboot 默认的错误信息格式

虽然上面这种使用姿势可以设置 http code,但是这种使用姿势有什么意义呢?

如果看过 web 系列教程中的:SpringBoot 系列教程 web 篇之全局异常处理 可能就会有一些映象,配合@ExceptionHandler来根据异常返回对应的状态码

一个推荐的使用姿势,下面表示当你的业务逻辑中出现数组越界时,返回 500 的状态码以及完整的堆栈信息

@ResponseBody
@ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleArrayIndexOutBounds(HttpServletRequest request, HttpServletResponse response,
        ArrayIndexOutOfBoundsException e) throws IOException {
    log.info("array index out conf!");
    return"aryIndexOutOfBounds: " + getThrowableStackInfo(e);
}
b. 装饰异常类

另外一种使用姿势就是直接装饰在异常类上,然后当你的业务代码中,抛出特定的异常类,返回的 httpcode 就会设置为注解中的值

/**
 * 异常类 + 注解方式,只支持标准http状态码
 *
 * @return
 */
@GetMapping("exception/500")
public String serverException() {
    thrownew ServerException("内部异常哦");
}

@GetMapping("exception/400")
public String clientException() {
    thrownew ClientException("客户端异常哦");
}

@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR, reason = "服务器失联了,请到月球上呼叫试试~~")
publicstaticclass ServerException extends RuntimeException {
    public ServerException(String message) {
        super(message);
    }
}

@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "老哥,你的请求有问题~~")
publicstaticclass ClientException extends RuntimeException {
    public ClientException(String message) {
        super(message);
    }
}

测试结果如下,在异常类上添加注解的方式,优点在于不需要配合@ExceptionHandler写额外的逻辑了;缺点则在于需要定义很多的自定义异常类型

➜  ~ curl 'http://127.0.0.1:8080/code/exception/400' -i
HTTP/1.1 400
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Jan 2020 01:37:07 GMT
Connection: close

{"timestamp":"2020-01-05T01:37:07.662+0000","status":400,"error":"Bad Request","message":"老哥,你的请求有问题~~","path":"/code/exception/400"}%

➜  ~ curl 'http://127.0.0.1:8080/code/exception/500' -i
HTTP/1.1 500
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Jan 2020 01:37:09 GMT
Connection: close

{"timestamp":"2020-01-05T01:37:09.389+0000","status":500,"error":"Internal Server Error","message":"服务器失联了,请到月球上呼叫试试~~","path":"/code/exception/500"}%

注意

  • ResponseStatus 注解的使用姿势,只支持标准的 Http Code(必须是枚举类org.springframework.http.HttpStatus

 

2. ResponseEntity

这种使用姿势就比较简单了,方法的返回结果必须是ResponseEntity,下面给出两个实际的 case

@GetMapping("401")
public ResponseEntity<String> _401() {
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("{\"code\": 401, \"msg\": \"未授权!\"}");
}

@GetMapping("451")
public ResponseEntity<String> _451() {
    return ResponseEntity.status(451).body("{\"code\": 451, \"msg\": \"自定义异常!\"}");
}

实测结果

➜  ~ curl 'http://127.0.0.1:8080/code/401' -i
HTTP/1.1 401
Content-Type: text/plain;charset=UTF-8
Content-Length: 34
Date: Sun, 05 Jan 2020 01:40:10 GMT

{"code": 401, "msg": "未授权!"}

➜  ~ curl 'http://127.0.0.1:8080/code/451' -i
HTTP/1.1 451
Content-Type: text/plain;charset=UTF-8
Content-Length: 40
Date: Sun, 05 Jan 2020 01:40:19 GMT

{"code": 451, "msg": "自定义异常!"}

从上面的使用实例上看,可以知道这种使用方式,不仅仅支持标准的 http code,也支持自定义的 code(如返回 code 451)

3. HttpServletResponse

这种使用姿势则是直接操作HttpServletResponse对象,手动录入返回的结果

a. setStatus
/**
 * response.setStatus 支持自定义http code,并可以返回结果
 *
 * @param response
 * @return
 */
@GetMapping("525")
public String _525(HttpServletResponse response) {
    response.setStatus(525);
    return"{\"code\": 525, \"msg\": \"自定义错误码 525!\"}";
}

输出结果

➜  ~ curl 'http://127.0.0.1:8080/code/525' -i
HTTP/1.1 525
Content-Type: text/plain;charset=UTF-8
Content-Length: 47
Date: Sun, 05 Jan 2020 01:45:38 GMT

{"code": 525, "msg": "自定义错误码 525!"}%

使用方式比较简单,直接设置 status 即可,支持自定义的 Http Code 返回

b. sendError

使用这种姿势的时候需要注意一下,只支持标准的 http code,而且 response body 中不会有你的业务返回数据,如

/**
 * send error 方式,只支持标准http状态码; 且不会带上返回的结果
 *
 * @param response
 * @return
 * @throws IOException
 */
@GetMapping("410")
public String _410(HttpServletResponse response) throws IOException {
    response.sendError(410, "send 410");
    return"{\"code\": 410, \"msg\": \"Gone 410!\"}";
}

@GetMapping("460")
public String _460(HttpServletResponse response) throws IOException {
    response.sendError(460, "send 460");
    return"{\"code\": 460, \"msg\": \"Gone 460!\"}";
}

输出结果

➜  ~ curl 'http://127.0.0.1:8080/code/410' -i
HTTP/1.1 410
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Jan 2020 01:47:52 GMT

{"timestamp":"2020-01-05T01:47:52.300+0000","status":410,"error":"Gone","message":"send 410","path":"/code/410"}%

➜  ~ curl 'http://127.0.0.1:8080/code/460' -i
HTTP/1.1 500
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Jan 2020 01:47:54 GMT
Connection: close

{"timestamp":"2020-01-05T01:47:54.719+0000","status":460,"error":"Http Status 460","message":"send 460","path":"/code/460"}%

从上面的 case 也可以看出,当我们使用 send error 时,如果是标准的 http code,会设置对响应头;如果是自定义的不被识别的 code,那么返回的 http code 是 500

4, 小结

上面介绍了几种常见的设置响应 http code 的姿势,下面小结一下使用时的注意事项

ResponseStatus

  • 只支持标准的 http code

  • 装饰自定义异常类,使用时抛出对应的异常类,从而达到设置响应 code 的效果

    • 缺点对非可控的异常类不可用

  • 结合@ExceptionHandler,用来装饰方法

ResponseEntity

形如:

return ResponseEntity.status(451).body("{\"code\": 451, \"msg\": \"自定义异常!\"}");
  • 我个人感觉是最强大的使用姿势,就是写起来没有那么简洁

  • 支持自定义 code,支持设置 response body

HttpServletResponse

  • setStatus: 设置响应 code,支持自定义 code,支持返回 response body

  • sendError: 只支持标准的 http code,如果传入自定义的 code,返回的 http code 会是 50文章来源地址https://www.toymoban.com/news/detail-848657.html

到了这里,关于SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Rust Web 全栈开发之自建TCP、HTTP Server

    Rust 编程语言入门 https://www.bilibili.com/video/BV1hp4y1k7SV WebService 服务器端Web App 客户端Web App(WebAssembly) Web框架:Actix 数据库:PostgreSQL 数据库连接:SQLx 全部使用纯Rust编写! 编写TCP Server和Client 标准库的std::net模块,提供网络基本功能 支持TCP和UDP通信 TcpListener和TcpStream 创建项目

    2024年02月06日
    浏览(29)
  • SpringBoot缓存注解@Cacheable之自定义key策略及缓存失效时间指定

    1. 项目依赖 本项目借助 SpringBoot 2.2.1.RELEASE  +  maven 3.5.3  +  IDEA  +  redis5.0 进行开发 开一个 web 服务用于测试 1. key 生成策略 对于 @Cacheable 注解,有两个参数用于组装缓存的 key cacheNames/value: 类似于缓存前缀 key: SpEL 表达式,通常根据传参来生成最终的缓存 key 默认的 redisK

    2024年02月19日
    浏览(30)
  • 微信小程序之自定义模态弹窗(带动画)实例 —— 微信小程序实战系列(8)(2)

    api如下: 示例: 这样的模态弹窗,充其量只能做个alert,提示一下信息。 但是并不能使用它来处理复杂性的弹窗业务,因此写了Michael从新自定义了一个,采用了仿原生的样式写法 wxml: button 弹窗标题 标题 标题 标题 标题 备注 确定 wxss: / button / .btn { width: 80%; padding: 20rpx

    2024年04月11日
    浏览(27)
  • Spring Security 6.x 系列【46】漏洞防护篇之安全相关的HTTP响应头

    有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.0.4 本系列Spring Security 版本 6.0.2 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo

    2024年02月07日
    浏览(31)
  • 若依框架下的自定义Exception抛出,返回code,msg不出错(spring boot)。

    若依框架下的自定义Exception抛出,返回code,msg不出错: 最近接的项目后台中,因为需要在app用到自定义的token验证(不用若依的那一套登陆token)来确保接口的安全性,需要在进入接口前使用aop切面的before来验证它的头(headers)是否符合条件。 先上代码: 当token出现不匹配

    2023年04月09日
    浏览(40)
  • php通过cURL爬取数据(3):CURLINFO_HTTP_CODE返回0的排查和解决方案

    在使用 curl 命令发送请求到域名地址,本地服务器需要进行 DNS 解析以获取域名对应的 IP 地址,否则,curl 命令将无法建立与目标服务器的连接。当使用 curl 命令发送请求时,curl 会尝试自动解析所提供的 URL 以获取 IP 地址。如果 DNS 解析成功,curl 将使用获取到的 IP 地址建立

    2024年02月09日
    浏览(49)
  • springboot上传文件到本地,并且返回一个http访问路径

    直接上代码,controller层代码: 然后配置和工具类: 上传工具类: 常量类  接下来讲一下思路: 1、首先我们是要把文件上传到项目的目录中,获取项目路径的方法是这个: 假如我们项目的路径是:D:/project/crm/admin,我们这里返回的路径就是D:/project/crm/admin/upload 2、文件上传

    2024年02月16日
    浏览(31)
  • springboot的@RestControllerAdvice作用和捕获自定义异常返回自定义结果案例

    @RestContrllerAdvice是一种组合注解,由@ControllerAdvice,@ResponseBody组成 @ControllerAdvice继承了@Component,反过来,可以理解为@RestContrllerAdvice 本质上就是@Component 本质上是一个类,泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller,@Service等的时候),我们就可以

    2024年02月03日
    浏览(27)
  • springboot实现webservice接口自定义返回值通过postman测试

    震惊~~都2023年了竟然还有人用webservice! maven添加依赖 添加配置文件 自定义拦截器 通过cxf实现wenservice服务返回结果是有一层固定包装的,类似下图,return标签里才是结果,如何完全自定义返回的结果数据呢?就需要上面的拦截器去掉外层的包装。 service类 实现类 接下来启动

    2024年02月16日
    浏览(37)
  • SpringBoot中通过自定义Jackson注解实现接口返回数据脱敏

    SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文,查询明文: SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文,查询明文_霸道流氓气质的博客-CSDN博客 上面讲的是数据库中存储密文,查询时使用明文的脱敏方式,如果是需要数据库中存储 明文

    2024年02月16日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包