前言:今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常。

一般系统的大致整体架构图如下:

因为本篇博客主要介绍的是API接口,其他的模块比如网关、Redis缓存、MQ消息中间件小伙伴们自行去补充。

一、前后端RESTful接口交互

前端和后端进行交互,前端按照约定请求URL路径,并传入相关参数,后端服务器接收请求,进行业务处理,返回数据给前端。

1.1、RESTful风格的URL路径设计

REST,即Representational State Transfer的缩写。翻译过来是表现层状态转换。实际上 REST 的全称是 Resource Representational State Transfer ,直白地翻译过来就是 “资源”在网络传输中以某种“表现形式”进行“状态转移” 。如果一个架构符合REST原则,就称它为RESTful架构。

REST由Roy Fielding在他的论文中提出。REST用来描述客户端通过某种形式获取服务器的数据,这些数据资源的格式通常是JSON或XML。同时,这些资源的表现或资源的集合是可以修改的,伴随着行为和关系可以通过多媒体来发现。在我看来,一种简单的理解就是:在设计API时,使用路径定位资源,方法定义操作,通过Content-Type和Accept来协商资源的类型。

  • 资源(Resource) :我们可以把真实的对象数据称为资源。一个资源既可以是一个集合,也可以是单个个体。比如我们的班级 classes 是代表一个集合形式的资源,而特定的 class 代表单个个体资源。每一种资源都有特定的 URI(统一资源标识符)与之对应,如果我们需要获取这个资源,访问这个 URI 就可以了,比如获取特定的班级:/class/12。另外,资源也可以包含子资源,比如 /classes/classId/teachers:列出某个指定班级的所有老师的信息

  • 表现形式(Representational):"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式比如 jsonxmlimage,txt 等等叫做它的"表现层/表现形式"。

  • 状态转移(State Transfer) :大家第一眼看到这个词语一定会很懵逼?内心 BB:这尼玛是啥啊? 大白话来说 REST 中的状态转移更多地描述的服务器端资源的状态,比如你通过增删改查(通过 HTTP 动词实现)引起资源状态的改变。ps:互联网通信协议 HTTP 协议,是一个无状态协议,所有的资源状态都保存在服务器端。

1.2、RESTful规范

方法动作

GET:查询操作,举个例子:GET /classes(获取所有班级)

POST:修改/添加操作,举个例子:POST /classes(创建班级)

PUT:更新操作,举个例子:PUT /classes/12(更新编号为 12 的班级)

DELETE:删除操作,举个例子:DELETE /classes/12(删除编号为 12 的班级)

PATCH :更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新),使用的比较少,这里就不举例子了。

接口路径命名规范

表示 API 的具体网址。实际开发中常见的规范如下:

接口网址尽量使用名词,避免使用动词,API 中的名词也应该使用复数 因为  RESTful API 操作(HTTP Method)的是资源(名词)而不是动作(动词),REST 中的资源往往和数据库中的表对应,而数据库中的表都是同种记录的"集合"(collection)。如果 API 调用并不涉及资源(如计算,翻译等操作)的话,可以用动词。比如:GET /calculate?param1=11&param2=33 。

不用大写字母,建议用中杠 - 不用下杠 _ 。比如邀请码写成 invitation-code而不是 invitation_code 。

善用版本化 API。当我们的 API 发生了重大改变而不兼容前期版本的时候,我们可以通过 URL 来实现版本化,比如 http://api.example.com/v1http://apiv1.example.com 。版本不必非要是数字,只是数字用的最多,日期、季节都可以作为版本标识符,项目团队达成共识就可。

RESTful为什么加版本号

所有的API必须保持向后兼容,必须在引入新版本API的同时确保旧版本API仍然可用。所以应该为其提供版本支持。必须在URL中嵌入版本编号,格式要求如下:http://URL/api/v1/*

一般来说,API接口是提供给其他系统或是其他公司使用,不能随意频繁的变更。然而,需求和业务不断变化,接口和参数也会发生相应的变化。如果直接对原来的接口进行修改,势必会影响线其他系统的正常运行。这就必须对api 接口进行有效的版本控制。

例如,添加用户的接口,由于业务需求变化,接口的字段属性也发生了变化而且可能和之前的功能不兼容。为了保证原有的接口调用方不受影响,只能重新定义一个新的接口。

  • http://localhost:8080/api/v1/user

  • http://localhost:8080/api/v2/user

Api 版本控制的方式:

  • 请求url 路径区分,在同一个域名下使用不同的url路径,test.com/api/v1/,test.com/api/v2

  • 域名区分管理,即不同的版本使用不同的域名,v1.api.test.com,v2.api.test.com

  • 请求参数区分,在同一url路径下,增加version=v1或v2 等,然后根据不同的版本,选择执行不同的方法。

实际项目中,一般选择第一种:请求url路径区分。因为第一种既能保证水平扩展,又不影响以前的老版本

1.3、RESTful URL设计

RESTful风格的url能实现自我功能的描述,清晰明了。

user/{uid}/friends  //用户/用户id/用户的朋友,表示用户的好友列表,语义清晰明了,符合RESTful风格

user/friends/uid    //不符合RESTful风格,url语义不顺畅

item/{id}/delete  //这里delete可以视为名词,商品/商品id/删除,语义清晰明了,符合RESTful风格

item/delete/{id}  //商品/删除/商品id,url语义不明了,不清晰

针对RESTful风格URL路径的传入参数的公共请求头的要求(如:app_version,api_version,device等),这里就不介绍了。

1.4、RestFul接口举例

Talk is cheap!来举个实际的例子来说明一下吧!现在有这样一个 API 提供班级(class)的信息,还包括班级中的学生和教师的信息,则它的路径应该设计成下面这样。

GET    /classes:列出所有班级
POST   /classes:新建一个班级
GET    /classes/{classId}:获取某个指定班级的信息
PUT    /classes/{classId}:更新某个指定班级的信息(一般倾向整体更新)
PATCH  /classes/{classId}:更新某个指定班级的信息(一般倾向部分更新)
DELETE /classes/{classId}:删除某个班级
GET    /classes/{classId}/teachers:列出某个指定班级的所有老师的信息
GET    /classes/{classId}/students:列出某个指定班级的所有学生的信息
DELETE /classes/{classId}/teachers/{ID}:删除某个指定班级下的指定的老师的信息

反例:

/getAllclasses
/createNewclass
/deleteAllActiveclasses

理清资源的层次结构,比如业务针对的范围是学校,那么学校会是一级资源:/schools,老师: /schools/teachers,学生: /schools/students 就是二级资源。

1.5、@GetMapping、@PostMapping、@PutMapping和@DeleteMapping

从Spring4.3开始引进了{@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping},提供了对Restful风格的支持,来帮助简化常用的HTTP方法的映射,并更好地表达被注解方法的语义。

  • @GetMapping,处理get请求

  • @PostMapping,处理post请求

  • @PutMapping,处理put请求

  • @DeleteMapping,处理delete请求

以@GetMapping和@PostMapping为例,Spring官方文档说:

@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。该注解将HTTP Get 映射到 特定的处理方法上。

@PostMapping 是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。该注解将HTTP Post 映射到 特定的处理方法上。


二、统一的API接口返回格式

着重介绍一下后端服务器如何实现把数据返回给前端,后端返回给前端我们一般用JSON体方式,定义如下:

{#返回状态码code:integer,     #返回信息描述message:string,#返回值data:object
}

2.1、CODE状态码

code返回状态码,一般小伙伴们是在开发的时候需要什么,就添加什么。

如接口要返回用户权限异常,我们加一个状态码为101吧,下一次又要加一个数据参数异常,就加一个102的状态码。这样虽然能够照常满足业务,但状态码太凌乱了

我们应该可以参考HTTP请求返回的状态码

下面是常见的HTTP状态码:
200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误

我们可以参考这样的设计,这样的好处就把错误类型归类到某个区间内,如果区间不够,可以设计成4位数。

#1000~1999 区间表示参数错误
#2000~2999 区间表示用户错误
#3000~3999 区间表示接口异常

这样前端开发人员在得到返回值后,根据状态码就可以知道,大概什么错误,再根据message相关的信息描述,可以快速定位。

2.2、Message

这个字段相对理解比较简单,就是发生错误时,如何友好的进行提示。一般的设计是和code状态码一起设计,如:

再在枚举中定义,状态码:

状态码和信息就会一一对应,比较好维护。

2.3、Data

返回数据体,JSON格式,根据不同的业务有不同的JSON体。

2.4、API接口统一返回使用举例

(1) 我们要设计一个返回体类Result

(2)控制层Controller

我们会在controller层处理业务请求,并返回给前端,以order订单为例

我们看到在获得order对象之后,我们是用的Result构造方法进行包装赋值,然后进行返回。小伙伴们有没有发现,构造方法这样的包装是不是很麻烦,我们可以优化一下。

(3)美观美化

我们可以在Result类中,加入静态方法,一看就懂

那我们来改造一下Controller:

上面我们看到在Result类中增加了静态方法,使得业务处理代码更加简洁。


三、设计一个返回体类ResultBean类

package com.hs.demo.pojo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** 统一返回 ResultBean:将所有的接口的响应数据的格式进行统一。** @Data 注解的主要作用是提高代码的简洁,使用这个注解可以省去代码中大量的get()、 set()、 toString()等方法;要使用 @Data 注解要先引入lombok,lombok 是什么,它是一个工具类库,可以用简单的注解形式来简化代码,提高开发效率。*/@Data
@ApiModel("固定返回格式")
public class ResultBean implement Serializable{private static final long serialVersionUID = 1L;/*** 错误码*/@ApiModelProperty("错误码")private Integer code;/*** 提示信息*/@ApiModelProperty("提示信息")private String message;/*** 具体的内容*/@ApiModelProperty("响应数据")private Object data;}

四、API全局返回码

描述API接口的共性返回码,API自定义的接口返回码请参阅对应API接口文档描述。

API全局返回码,就是每次调用接口时,可能获得正确或错误的返回码,开发者可以根据返回码信息调试接口,排查错误。

百度Open API错误码定义:

错误码

错误描述

Error Description

0

成功

Success

1

未知错误

Unknown error

2

服务暂不可用

Service temporarily unavailable

3

未知的方法

Unsupported openapi method

4

接口调用次数已达到设定的上限

Open api request limit reached

5

请求来自未经授权的IP地址

Unauthorized client IP address

6

无权限访问该用户数据

No permission to access user data

7

来自该refer的请求无访问权限

No permission to access data for this referer

100

请求参数无效

Invalid parameter

101

api key无效

Invalid API key

104

无效签名

Incorrect signature

105

请求参数过多

Too many parameters

106

未知的签名方法

Unsupported signature method

107

timestamp参数无效

Invalid/Used timestamp parameter

109

无效的用户资料字段名

Invalid user info field

110

无效的access token

Access token invalid or no longer valid

111

access token过期

Access token expired

210

用户不可见

User not visible

211

获取未授权的字段

Unsupported permission

212

没有权限获取用户的email

No permission to access user email

800

未知的存储操作错误

Unknown data store API error

801

无效的操作方法

Invalid operation

802

数据存储空间已超过设定的上限

Data store allowable quota was exceeded

803

指定的对象不存在

Specified object cannot be found

804

指定的对象已存在

Specified object already exists

805

数据库操作出错,请重试

A database error occurred. Please try again

900

访问的应用不存在

No such application exists


五、授权/令牌请求接口返回码

描述应用发起授权请求或令牌请求时,开放平台的返回码。

错误码

错误描述

Error Description

10000

非法的请求参数

Invalid request

10001

用户认证失败

Invalid client

10002

非法的授权信息

Invalid grant

10003

应用没有被授权,无法使用所指定的grant_type

Unauthorized client

10004

grant_type字段超过定义范围

Unsupported grant_type

10005

scope信息无效或超出范围

Invalid scope

10006

提供的更新令牌已过期

Expired token

10007

redirect_uri字段与注册应用时所填写的不匹配

Redirect_uri mismatch

10008

response_type参数值超过定义范围

Unsupported response type

10009

用户或授权服务器拒绝授予数据访问权限

Access denied


参考文档:

SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!

RestFul API 简明教程

restful接口实战 更新用put 新增用post 获取get 删除detele

公司前端和后端因为接口吵起来啦,还列了 5 锅罪

API接口的RESTful设计相关推荐

  1. 对外API接口的安全性设计及鉴权方式

    对外API接口的安全性设计及鉴权方式 API鉴权方式 API Key + API Secret实现API鉴权 Cookie + Session实现API鉴权 token机制实现API鉴权 API接口的 ...

  2. API接口应该如何设计?

    在日常开发中,总会接触到各种接口.前后端数据传输接口,第三方业务平台接口.一个平台的前后端数据传输接口一般都会在内网环境下通信,而且会使用安全框架,所以安全性可以得到很好的保护.这篇文章重点讨论一下提 ...

  3. 四连问:API 接口应该如何设计?如何保证安全?如何签名?如何防重?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:cnblogs.com/jurendage/p/126538 ...

  4. API 接口应该如何设计?如何保证安全?如何签名?如何防重?

    点击蓝色"架构文摘"关注我哟 加个"星标",每天上午 09:25,干货推送! 来源:https://www.cnblogs.com/jurendage/p/12 ...

  5. c# api接口管理

    在一个大型项目中,API接口的数量会不断增加,这会使API管理过程变得非常困难.因此,如何进行有效的管理就变得至关重要.下面是一些可以用来管理API接口的方法可以用来管理API接口的建议: 一.组织接 ...

  6. 64如何传入后台_如何保证API接口数据安全?

    (给ImportNew加星标,提高Java技能) 转自:Java互联网架构师小马 链接:https://www.jianshu.com/p/e2d362ede89f 前后端分离的开发方式,我们以接口为 ...

  7. 安全架构-api接口安全设计

    安全架构-api接口安全设计 安全架构系列文章是从api接口的安全性设计引入的,讨论了api的业务安全-幂等性设计,传输安全,加签名和加解密,介绍了对称加密,非对称加密的常用算法的实现.继续回到api ...

  8. restful api接口设计

    技术由来: 互联网早期,页面请求和并发量不高,且移动端未盛行时对接口要求不高,使用动态页面(jsp)就能满足绝大多数的使用需求.但是随着互联网和移动设备的发展,人们对Web应用的使用需求也增加,传统的 ...

  9. restful 参数带斜杠_SpringCloud实战:Restful架构API接口经典设计误区

    前言 目前微服务架构盛行,发现很多同学设计业务API接口时,写法五花八门.现总结下目前项目上,设计业务API接口的经典误区写法. API接口设计经典误区写法 1.查询某个对象接口: GET /app/ ...

最新文章

  1. MS UC 2013-0-虚拟机-标准化-部署-2-模板机-制作-2-设置-虚拟机
  2. EditPlus 3.5 版已经发布
  3. error while loading shared libraries:libmysqlclient.so.18 错误
  4. gitlab 自动推送代码到gitee_Gitlab 利用 Webhook+jenkins 实现自动构建与部署
  5. select框怎么传值到服务端_前端简历中的项目经历怎么突出亮点?
  6. linux之通过tail命令动态跟踪日志文件里面的末尾信息
  7. 团队项目讨论及计划修订版
  8. 95-32-010-ChannelPipeline-ChannelPipeline简介
  9. java 获取js html_JS获取网页中HTML元素的几种方法
  10. 2018结束,新的开始 - CMU学弱走上技术之路
  11. 国内外智慧医疗云平台调研
  12. 九月英语--不同以往的感觉
  13. python中localtime和gtime的区别及时区计算的代码
  14. ct上的img表示什么_X线/CT/MR影像片子上的标识你是否都认识?
  15. .Net Core MVC引入static静态变量到.cshtml页面
  16. 纹理打包器 TexturePacker
  17. 笔记本F1音量键常亮,电脑没声音?这里有妙招。
  18. 柴达木光伏+农业跨界融合新态势
  19. uva 672 Gangsters( dp )
  20. uM计算机组成原理,计算机组成原理_课程设计报告.doc

热门文章

  1. mysql 查询表 第一列报错_MySQL----DQL(查询数据库表中数据)
  2. OpenCV4学习笔记(41)——ORB特征提取描述算法
  3. 什么是io?程序员该怎么理解io
  4. [区块链安全-链上分析]链上安全分析及相关POC编写
  5. CDR插件开发之CPG插件003 - 使用VS2019编译CDR类型库 VGCoreAuto.tlb
  6. using(){}的使用
  7. nodejs+express+mysql 之 简单的在线HTML编辑器
  8. 海康API——获取监控点预览取流URL,获取的rtmp流不能播放
  9. 解决itunes默认备份在C盘,C盘空间占用问题
  10. fcbf特征选择步骤_一文读懂 聚类特征选择