大前端前提下,开发采用前后端分离的方式,前端和后端主要通过接口进行分离,
后端开发接口,前端使用接口,前后端接口开发告一段落以后,接口联调差不多就进入开发尾声,准备送测了。
那么,对接口的约束和规范就尤为重要,以下文档是我负责参与技术委员会,
基于restful架构制定的web接口规范。具体内容如下:
- 1. 概述
- 1.1. 背景及目的
- 1.2. 适用范围
- 1.3. 描述方式约定
- 1.4. 结构说明
- 2. 请求报文 Headers
- 2.1. 常规项 General
- 2.1.1. 请求地址 Request URL
- 2.1.1.1. 协议方案名
- 2.1.1.2. 域名,端口
- 2.1.1.3. URL路径中优先体现服务和资源
- 2.1.1.4. URL路径命名规范
- 2.1.1.5. 版本号
- 2.1.1.6. 数据变量
- 2.1.1.7. 避免传递无关参数
- 2.1.1.8. URL最大长度限制为2083字节
- 2.1.1.9. 规定字段必须按照规范命名
- 2.1.2. 请求方法 Request Method
- 2.1.3. 状态码 Status Code
- 2.2. 响应首部 Response Headers
- 2.3. 请求首部 Request Headers
- 2.4. 传参 Query / Body (form data)
- 3. 响应 Response
- 3.1.【强制】响应数据格式规范
- 4. 其他规范 Other
- 4.1.【强制】HTTP HEADER命名规范
- 4.2. 传输规范
- 4.2.1.【强制】传输协议规范
- 4.2.2. 【强制】HTTP GZIP压缩传输规范说明
- 4.3. 接口安全相关规范
- 4.3.1.【强制】签名规范
- 4.3.2.【强制】敏感数据加密规范
- 4.3.3.【强制】登录接口特殊要求
- 4.4.4. 【强制】接口相关的Cookie使用规范
- 参考文档
需要确认的问题列表:
序号 | 是否完成 | 问题说明 | 解决方案 |
1 | URL路径/api/xxx,his/,这一块的表现形式 | 已经补充 至: 2.1.1.3. 路径中优先体现服务和资源 | |
2 | URL路径命名规范,动词放前面还是后面 | 已经补充 至: 2.1.1.4. URL路径命名规范 | |
3 | 版本号问题如何解决 |
| |
4 | query非业务数据不传,解决方法 |
| |
5 | 请求方法,是强制2个,还是5个 |
| |
6 | lang 返回语言,这个字段怎么设计(JSON数据类型?) | 多语言设计,是需要继续探讨的。第一版规范暂时不包含。 | |
7 |
| ||
8 | 《公司应用错误码规范》 |
| |
9 | 补充request-id | 已经补充 至: 2.3. 请求首部 Request Headers | |
10 | 业务异常,返回状态码问题 | 和xx又讨论一下次,结论整理如下: 1. 将异常分为3个类型:用户错误请求异常(BadRequestException)、系统异常(Exception)、业务异常(ServiceException) 2. 业务异常,http status 使用 200,返回数据内部区分具体不同 {code, message} 3. 系统异常,http status 使用 500,返回数据 = {code: 特定编码, message: 一句友好的提示, errorInfo: 用于定位问题(可能有堆栈信息);未了避免返回敏感信息,在正式环境将屏蔽} 4. 用户错误请求异常,https status 使用 400, 返回数据 = {code: 特定编码,message: 错误原因,用于辅助前端同学调整或者参加参数校验} 5. 接口请求中如果出现 400 或 500,开发、测试同学一定要关注。500问题由后端同学处理;400问题由前端同学处理。 |
1. 概述
1.1. 背景及目的
为了更好的提高前后端协同开发效率,降低维护难度,有必要对接口进行规范。基于目前公司现状,本规范旨在统一前后端之间、及各业务系统之间HTTP API接口调用与交互。
1.2. 适用范围
所有新上线服务的内网/外网HTTP/HTTPS接口,建议旧系统再改造上线过程中也参照逐步向本规范靠拢,最终达到所有系统HTTP接口都按统一规范定义。
1.3. 描述方式约定
【强制】表示该条规则必须遵守,【推荐】表示该条规则大多数情况下遵守,是建议性规则
每个大的规则下只要有一条子规则是【强制】规则,这条大规则会标记为【强制】,但并不表示该大规则下的其它【推荐】子规则也是【强制】
1.4. 结构说明
为了方便理解,以下内容按照chrome中network结构进行说明:
2. 请求报文 Headers
2.1. 常规项 General
2.1.1. 请求地址 Request URL
https:
//
域名:port
/api/user-center/customers?limit=25&offset=50&fields=id,name,age
2.1.1.1. 协议方案名
使用http:或https:等协议方案名获取访问资源时要指定协议类型。
2.1.1.2. 域名,端口
每个业务使用的域名会有差异。北吉熊使用的域名是 power.medcloud.cn
一般的web接口,向前端暴露的,只用80端口,平时本地调试使用的端口不做限制。
2.1.1.3. URL路径中优先体现服务和资源
api/user-center/customers
这个例子中,user-center是服务名称,而customers代表资源名称。不要在api/和user-center/之间再添加其他部分。
描述要尽量简短,也要清晰地体现其定位和差异,避免未来其他服务或资源出现重名。
2.1.1.4. URL路径命名规范
正确示例:/api/user-center/customers/43
一般的接口,不要在路径中添加动词,因为大部分的操作行为,都通过HTTP Method来表示了。
获取多个客户,数据集合:
METHOD: GET
/api/user-center/customers?current=16&size=20&fields=id,name,age
获取某个客户的所有订单:
METHOD: GET
/api/user-center/customers/448207/orders
参考依据:微软Azure接口设计 , http-api-design-ZH_CN, HTTP API Design
2.1.1.4.1.【强制】路径名称只能包含小写英文字母、数字和短划线,且第一个字符必须是小写英文字母,单词之间用短划线分隔;
正确示例:
/api/user-center/customers/43
错误示例:
/api/user_center/customers/43/get_token 应该是短划线 /api/usercenter/customers/43/get_token 单词之间分隔/api/userCenter/customers/43/get_token 不应该用小驼峰
2.1.1.4.2.【强制】使用名词表示资源,只有在名词无法表示接口含义时,才使用动词作为补充的action动作
获取单个客户:
METHOD: GET
/api/user-center/customers/448207
某些特殊情况下,需要指定动作,可以添加动词。如非必要,还是别用。
对某个客户做重置操作:
METHOD: GET
/api/user-center/customers/448207/actions/reset
2.1.1.4.3.【推荐】URL路径末尾建议不加.json等后缀,比如.xml, .htm等都不建议。(文件名本身带有后缀名的静态文件URL路径不在本规范的限制内)
2.1.1.5. 版本号
【强制】在Request Header中标识版本号。
// 通过自定义头设置版本1
X-Api-Version: 1
// 通过自定义头设置版本2
X-Api-Version: 2
// 通过自定义头设置版本2.1
X-Api-Version: 2.1
注意:不要在path中添加版本号。版本是指接口的版本(对应Java代码中某个具体方案),不是整个服务的版本。
2.1.1.6. 数据变量
接口请求和响应数据中的变量名用小驼峰命名。
接口请求和响应数据中的变量名只能包含大小写字母、数字,变量中每个单词首字符必须是字母,第一个单词首字母必须是小写字母,其它单词首字母必须大写,单词之间无分隔字符。
正确示例:companyLicenceRegNo 小驼峰命名方式
错误示例:CompanyLicenceRegNo、companylicenceRegNo、company_LicenceRegNo、company_licence
正确示例:?userName=xxxx&password=xxxxx
错误示例:?user_name=xxxx&Password=xxxxx
错误示例:?username=xxxx&password=xxxxx
错误示例:?UserName=xxxx&password=xxxxx
2.1.1.7. 避免传递无关参数
北吉熊系统中很多接口都要传一些通用参数,这些参数比较冗余,很多时候,后端服务通过token都能查出来。
要尽量避免无用参数的传递。
另外,在支持cookie的浏览器中,也要通过服务端程序写token,就不需要前端显式地传递了
2.1.1.8. URL最大长度限制为2083字节
【强制】URL最大长度限制为2083字节,包含?问号后面的query部分。(IE 2083, chrome 8182, firefox 65536, Safari 80000, Opera 190000)
2.1.1.9. 规定字段必须按照规范命名
【强制】涉及以下参考表中的字段必须按参考表中的名称命名,字段层级和数据类型格式要符合参考表说明的格式要求。
通用命名字段参考《HTTP通用命名参数》:
字段名 | JSON数据类型 | 字段含义 | 备注 |
current | Number | 查询的页码,以1为第一页 | 仅分页场景【强制】 |
size | Number | 查询的分页大小,默认10 | 仅分页场景【强制】 |
medicalInstitutionId | String | 机构ID | 所有ID类的字段,如果后端是Long类型,传给前端,必须用字符串,不能以数字形式传递。 |
chainMedicalInstitutionId | String | 连锁机构ID |
|
patinetId | String | 患者ID |
|
|
| 其它后续讨论补充 |
|
2.1.2. 请求方法 Request Method
常用的HTTP动词有下面五个(括号里是对应的SQL命令)。
【强制】每一个HTTP接口,实现时必须明确指定允许的HTTP Method,不允许默认。
【强制】HTTP Method用途分类的规定,示例:《HTTP Method 代码示例》、《HTTP Method 报文示例》。
方法名称 | 说明 | 举例 | 规范 |
【强制】GET(SELECT) | 从服务器取出资源(一项或多项) | 查询业务数据列表,查询业务数据详情 /api/user-center/customers?limit=25&offset=50&fields=id,name,age /api/user-center/customers/448207 /api/user-center/customers/448207/orders | query上送 (空值规范,为空不传,注意编码和解码) |
【推荐】DELETE(DELETE) | 从服务器删除资源 | 删除指定数据 /api/user-center/customers/448207 | |
【强制】POST(CREATE) | 新建一个资源 | 新增业务数据,比如:发起交易(生成新交易),用户注册,用户登录 以下是添加一个客户 /api/user-center/customers/ | JSON格式字符串作为HTTP BODY上送 (文件上传接口除外) |
【推荐】PUT (CREATE或UPDATE) | 新建或更新资源,如果存在,就更新,如果不存在,就新建。客户端可提供有变更的字段,但必须有唯一性标识,可以在路径中表示。 | 以下是添加或创建一个客户,路径特殊之处在于,带了id /api/user-center/customers/448207 | |
【推荐】PATCH(UPDATE) | 在服务器更新资源(客户端提供改变的属性) | 客户端上传部分字段数据,可以理解为对数据打个小补丁。特殊之处在于,字段只包含变更了的,没变更的字段不包含进JSON数据中。 /api/user-center/customers/448207 |
{
name: "张三",
age: 18
}
以下内容是对上表的详细说明:
- 五个方法,两个强制,三个推荐
- 【强制】GET和DELETE请求数据使用查询参数(query) 传
- 【强制】POST/PUT/PATCH请求数据采用JSON格式字符串作为HTTP BODY提交,文件上传接口除外;
- 【推荐】文件上传接口允许使用表单提交(application/x-www-form-urlencoded或者multipart/form-data),UTF-8编码格式,可以增加一个MD5校验值参数,MD5校验无需盐值。
- 【推荐】需要支持探活的接口,实现时必须支持Method为HEAD的请求
- 【强制】请求HTTP HEADER中用"Content-Type"指明请求数据格式,使用"Accept"指明期望返回的数据格式,
示例1(请求数据格式和期待响应数据格式都是JSON):
Content-Type: application/json;charset=UTF-8Accept: application/json;charset=UTF-8
示例2(请求数据格式表单,期待响应数据格式为JSON):
Content-Type: application/x-www-form-urlencoded;charset=utf-8Accept: application/json;charset=UTF-8
7.【推荐】JSON请求和响应数据中的空值规范
本条的目的:为了简化前端判断逻辑,减少字段有无的判断和类型判断。数据字段不存在等同于Java对象中该字段值为空指针null
【推荐】请求数据中非必填JOSN字段不存在时,则不填该字段,适用于所有JSON类型。
【推荐】响应数据中非必填JOSN字段不存在时,则不填该字段,适用于所有JSON类型。
2.1.3. 状态码 Status Code
【推荐】按照HTTP协议对STATUS状态码的定义,不同情况返回适当的状态码,但禁止使用HTTP STATUS状态码来表示业务逻辑的不同结果,比如:用户不存在时也应返回200,而不是404。
【强制】权限验证不通过时,必须返回403状态码,以便于框架模块统一截获作适当的处理。了解更多详情《HTTP STATUS 状态码》
服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)
- 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
- 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
- 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
- 204 NO CONTENT - [DELETE]:用户删除数据成功。
- 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
- 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
- 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
- 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
- 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
- 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
- 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
- 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
状态码的完全列表参见这里。
2.2. 响应首部 Response Headers
Content-Type
Accept
合并到
2.1.2
2.3. 请求首部 Request Headers
Content-Type 和
Accept
请参考
2.1.2
在请求头中,还需要添加 Request-Id,以方便后端查日志查问题。其值为UUID。
X-Request-Id: 7c129eb1-c479-47bb-9c73-d263e2673026
2.4. 传参 Query / Body (form data)
合并到 2.1.2. 请求方法 Request Method
3. 响应 Response
响应json结构如下图:
3.1.【强制】响应数据格式规范
3.1. 1.【强制】响应数据使用JSON格式
3.1. 2. 【强制】响应数据JSON格式要求:code、msg和data必须是0级字段,_st、code必填字段,code != 0 (失败)时msg必填。
3.1. 3. 【强制】响应数据用JSON String类型表示Java Long类型数据
3.1. 4. 【强制】涉及以下参考表中的字段必须按参考表中的名称命名,字段层级和数据类型格式要符合参考表说明的格式要求,
通用字段命名参考:
字段名 | 字段层级 | JSON数据类型 | 字段含义 | 备注 |
_st | 0 | Number | 服务器时间 | 【强制】必须严格符合《公司应用错误码规范》
|
code | 0 | Number | 响应结果状态/错误码 0:表示成功 非0:表示失败 | |
msg(但his系统的错误描述为message) | 0 | String | 错误描述(外部描述) 非0时,返回msg。 | |
lang(his系统有,scrm系统没有) | 0 | String | 语言 | |
data | 0 | Object | 响应业务数据 | |
data.current | 1 | Number | 分页页码,以1为第一页 | 仅分页场景【强制】 |
data.size | 1 | Number | 分页大小 | 仅分页场景【强制】 |
data.pages | 1 | Number | 总页数 | 仅分页场景【强制】 |
data.total | 1 | Number | 总记录数 | 仅分页场景【强制】 |
data.records | 1 | Array | 数据列表 | 仅分页场景【强制】 |
|
|
| 其它后续讨论补充 |
|
3.1.5 【强制】错误码字段及格式定义必须符合《公司应用错误码规范》
正确示例:
{
"_st": 1620133767482,
"code": 407,
"msg": "机构异常"
}
正确示例:
{
"_st": 1619781822535,
"code": 0,
"data": {
"appointmentBeginTime": 1619917200000,
"appointmentEndTime": 1619919000000,
"appointmentId": 5810,
"appointmentMemo": "1111111111111121111",
"appointmentReason": "121",
"appointmentStatus": 6,
"arrearsFlag": false,
"birthday": "1999-04-30",
"doctorId": 4800,
"doctorName": "大白医生",
"patientAge": "22",
"patientGender": 1
}
}
正确示例:
{
"_st": 1619781822535,
"code": 0
}
4. 其他规范 Other
4.1.【强制】HTTP HEADER命名规范
4.1 .1【强制】自定义HTTP HEADER名称必须由大小写字符、数字和连字符-构成,必须以 "X-" 为前缀,单词之间用"-"连字符分隔,每个单词首字符必须是大写字母(不能是数字),其它字母小写,但单词本身是首字母简称的则全部大写,比如:X-Salt-Version,X-AES-Key,X-UUID-*
4.1.2【推荐】涉及以下参考表中的Header的必须按参考表中的名称命名,格式要符合参考表说明的格式要求。
自定义HEADER名称参考:
HEADER名称 | 用途 | 字段值格式 | 可选说明 | 备注 |
X-Token | 访问令牌 | 字符串 |
|
|
X-Refresh-Token | 刷新令牌,通常不传输,用于令牌刷新相关操作 |
|
|
|
X-Salt-Version | 当前数据签名使用的salt盐值版本 | 字符串 |
| 比如: X-Salt-Version: 1 |
X-Key-Version | 当前数据加密使用的加密密钥版本 | 字符串 "加密算法-密钥版本" |
| 比如: X-Key-Version: aes-001 |
X-Timestamp | 请求/响应时间戳,签名用做nonce随机值 |
|
|
|
X-Sign | 签名(值) | 字符串 |
|
|
4.2. 传输规范
4.2.1.【强制】传输协议规范
4.2.1.1 【推荐】内网接口采用HTTP传输,端口号不得以*443结尾,比如不使用8443,7443等端口(容易触发部分软件中的BUG);除中间件等特殊开源软件外,内网HTTP接口一般用8080端口;
4.2.1.2 【强制】外网接口除特殊情况外必须采用HTTPS传输,特殊情况的必须备案登记,并经技术委员会特例审批。外网HTTPS必须使用默认端口号443,外网HTTP必须80端口
4.2.2. 【强制】HTTP GZIP压缩传输规范说明
压缩传输时采用HTTP协议标准定义的方式进行,本条规范仅仅时对协议标准的解释说明,但XX科技仅限使用GZIP压缩数据格式,不能使用deflate(ZLIB)等其它格式,以简化各系统实现。
客户端在请求HTTP Header中用 Accept-Encoding: gzip,明确告知服务端,本客户端支持的压缩格式
服务端在响应HTTP Header中用 Content-Encoding:gzip 指示客户端需要对内容进行GZIP解压缩,也可以返回未压缩的内容,如果内容没有压缩时,禁止返回Content-Encoding
响应HTTP Header中Content-Type指明压缩前的内容格式,如: Content-Type: application/json;charset=UTF-8
响应HTTP Header中Content-Length指明压缩后的内容长度
HTTP/1.1 协议中的压缩格式说明表:
格式标识名 | 格式说明 | 备注 |
gzip | GZIP数据格式 | RFC 1952
|
deflate | ZLIB数据格式 | RFC 1950 RFC 1951(IE浏览器) |
4.3. 接口安全相关规范
4.3.1.【强制】签名规范
4.3.1.1.【强制】签名采用SHA256算法,新系统一律禁止使用MD5签名
4.3.1.2.【强制】签名运算时必须要有SaltKey盐值和nonce随机值参与运算,即SHA256(plainText+saltKey+nonce),以便同时满足防篡改和防重放攻击的作用。
4.3.1.3.【强制】内网服务间接口除非特殊要求外,不进行签名和验签。
4.3.1.4.【推荐】公网接口要求签名和验签。
4.3.1.5.【推荐】签名和验签过程建议在业务网关侧处理,不建议在内部业务系统中处理签名和验签。
4.3.1.6. 【强制】签名SaltKey盐值必须支持平滑更换要求。
4.3.1.7.【推荐】签名SaltKey盐值平滑更换方式,建议通过在HTTP Header中指定"X-Salt-Version: xxx"指明当前盐值版本,来支持盐值过渡。
4.3.2.【强制】敏感数据加密规范
4.3.2.1 【强制】对于密码和密钥类极度敏感数据必须采用RSA非对称加密算法加密,RSA密钥的长度必须大于1024。
4.3.2.2.【强制】接口请求和响应中的普通数据加密要求采用AES对称加密算法。
4.3.2.3 【推荐】外网接口请求和响应中的一般敏感数据推荐在网关则统一对整个Body加解密。
4.3.2.4 【强制】加密密钥支持平滑更换要求。
4.3.2.5 【推荐】加密密钥平滑更换方式,建议通过在HTTP Header中指定"X-Key-Version: aes-xxx" 指明当前密钥版本,来支持密钥过渡。
4.3.3.【强制】登录接口特殊要求
4.3.3.1. 【强制】外网接口禁止使用Http Basic认证(因为是base64(用户名:密码) 明文传输)。
4.3.3.2. 【强制】密码禁止明文传输(包括明文Base64转换后的值),只能传密码的SHA256摘要,或者非对称加密后的密文。
4.4.4. 【强制】接口相关的Cookie使用规范
4.4.4.1. 【强制】Cookie必须加上Secure和HttpOnly属性,必须设置有效期。
HTTP HEADER 示例:
Set-Cookie: key=value; Expires=date; Path=path; Domain=domain; Secure; HttpOnly
参考文档
https://geemus.gitbooks.io/http-api-design/content/en/requests/downcase-paths-and-attributes.html
https://tools.ietf.org/html/rfc2616
https://tools.ietf.org/html/rfc1738
https://tools.ietf.org/html/rfc2396
https://tools.ietf.org/html/rfc3986
https://tools.ietf.org/html/rfc7159
https://tools.ietf.org/html/rfc8259
信息创造价值, 知识就是力量。