后端http返回体浅析

9 阅读5分钟

主要方式

第一种:区分http状态与业务状态

正常:http -> 2xx

{
    code: 200,
    message: "成功",
    data: object
}

异常: http -> 2xx

{
    code:200,
    message: "错误提示信息",
    data: object
}

第二种:http状态与业务状态统一

正常:http -> 2xx

{
    code: 200,
    message: "成功",
    data: object
}

异常: http -> 3xx、4xx、5xx

{
    message: "错误提示信息",
    .....
}

其实目前来看使用哪一种都能实现相关业务,只要组内达成一致,并没有谁比谁优劣,但是基于目前的职业经历(主营后端,也写过vue、react的一些前端),还是比较推崇第一种方式的。

1.异常处理边界的问题

正常情况下,我们的确需要将异常系统抛出给调用方处理,但是这是单个系统内部方法调用的,目前基于http请求的服务调用,如果简单的将异常抛出,那么就会导致上游系统混乱,无法判定抛出的异常是调用参数不对,还是下游系统狗带了,直接抛出又不符合系统安全要求(如果你的系统不在意安全要求,那么你来讨论这个就没有意义)。

2.使用对象的考虑

系统的使用人是真实的人,提示信息的准确与否同样决定了用户友好度与交互设计的优劣,这也是为什么要对错误进行分类,毕竟准确友好的错误提示不仅能增加产品体验还能快速定位问题,所以到了前端来说,前端就需要区分哪些信息应该展示给客户,哪些信息不能展示给客户,单独的http状态码并不能帮助前端确认是否应该提示(当然,也有人说使用目前http协议中未使用的状态码,此情况后续说明)

从头开始讲

为什么会有http状态码?

这里就不赘述了,需要了解的可以移步超文本传输协议

  1. 信息响应 (100199)
  2. 成功响应 (200299)
  3. 重定向消息 (300399)
  4. 客户端错误响应 (400499)
  5. 服务端错误响应 (500599)

从网络的七层模型我们可以知道,网络本身并不可靠,超文本协议中定义了各种状态码用来处理一个http请求的各种状态,那么最主要的就有个问题,这个状态码是给谁用的

所有的状态描述中,都是在描述C/S模式下的各种状态,那么业务状态是否也是C/S间的状态?

如何选取

通常我们在选择标准的时候总是希望通用与规范,但是实际情况往往是通用的一定大而空,规范的一种小而精,就像物理学界在用一个公式代表所有力一样,程序开发中也是希望有一个规范能代表所有情况,但是目前来看,这种情况不存在,那么如何选取就成了关键点。

易用性

两者相同,不管是第一种方式还是第二种方式,在现有的各种语言中都有通用的处理,所以处理上都不会多很多工作量,如:

java中的的事实通用框架spring提供了ExceptionHandler处理方式

OpenFeign中的ErrorDecoder也能统一处理异常返回

react、vue的插件axios都提供的统一异常返回的处理方式

安全性

严格意义上来说只要后端处理的合适,不管是第一种方式方式第二种方式都能够保证安全性,但是按照以往的经验,如何准确而且不过多的处理异常是个问题。

1、可预期异常:此类异常通常用于业务校验,为了统一格式的处理,我们会在业务代码中显示的抛出异常,统一处理异常提示,便于国际化、异常分类等处理。

2、不可预期异常:通常是因为各种奇奇怪怪的原因导致的非预期异常,比如数据库访问超时、下游服务下线等,既不能预期,也不能放任,通常都会进行统一的异常拦截,防止将堆栈式的异常信息抛给客户。

所以在安全性上来说,只要进行了统一的异常拦截,异常的堆栈信息就不会抛给前端,在安全性上面就符合要求。

为什么会在意堆栈信息呢?因为理论上是不存在的绝对安全的系统的(这个就推荐大家看一部电影《我是谁》),所有的防护手段其实都是在增加破解与攻击的难度与成本,但是如果我们抛出堆栈信息,将本身黑盒的系统,呈现了一部分系统内部结构,降低了攻击方的成本,也就越不安全(参考现在的密码为什么都要大小写字母加特殊符号,以现在的个人计算机性能来说,超过6位的复杂密码的暴力破解基本就无解)。