跳到主要内容

RESTful API 规范

备注

服务端 API 推荐使用以下语言和框架实现:

基础约定

协议和域名

协议

总是启用 HTTPS 协议

域名

API 应该与前端页面部署在不同的域名

https://api.example.com/
CORS 支持

服务端 API 与前端页面在不同域名时,应该使用 CORS 避免跨域。

备注

跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。

出于安全原因,浏览器限制从脚本内发起的跨源 HTTP 请求。 例如,XMLHttpRequest 和 Fetch API 遵循同源策略。 这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确CORS响应头。

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

CORS 请求失败会产生错误,但是为了安全,在 JavaScript 代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

路径

  • 接口路径以 /api/{version}/api 开头
正面例子 👍
/api/product
/v7/api/product
反面例子 👎
/biz/product
/biz/api/product

注意:一个产品无论后端有多少个服务组成也应该只有一个 API 入口

正面例子 👍
/api/product
/api/order
反面例子 👎
/product-service/product
/order-service/order
  • 路径命名应该使用中划线命名法,而非驼峰命名法 或 下划线命名法
正面例子 👍

中划线命名法

/api/product-categories
反面例子 👎

下划线命名法

/api/product_categories

驼峰命名法

/api/productCategories
  • 接口路径使用资源名词而非动词,比如 /api/product /api/order动作应由 HTTP Method 体现,资源组可以进行逻辑嵌套。
正面例子 👍
POST /api/product
反面例子 👎
POST /api/create-product
  • 接口设计面向开放接口,而非单纯前端业务

要求我们在给结构路径命名时候面向通用业务的开放接口,而非单纯前端业务。

以获取筛选表单中的任务字段下拉选项为例:

正面例子 👍
/api/product
反面例子 👎
/api/product-with-select

虽然这个接口暂时只用在表单的下拉选择中,但是需要考虑的是在未来可能会被用在任意场景,因此应以更通用方式提供接口交由客户端自由组合

身份认证

API 的身份认证应该使用 OAuth 2.0 框架。

Authorization: <type> <credentials>
提示

服务端推荐使用 Spring Security 实现

用户信息应使用身份认证获取,不依赖客户端id

正面例子 👍
POST /api/user
Authorization: Bearer b25ed4f6b1ec69afea62dc248e52b8b24c090dbf3c07046bf8ff8a6b

{
"nickname": "meiko"
}
反面例子 👎
POST /api/user

{
"userId": "OjP9LDwma1bMA68x8kzBm",
"nickname": "meiko"
}

请求方法

规范使用 HTTP 方法,参见 MDN Web Doc

Methods操作对应 SQL示例路径
GET读取(Read):从服务器获取列表数据SELECT/product
GET读取(Read):从服务器获取单条数据SELECT/product/:id
POST创建(Create):在服务器创建数据INSERT/product
PUT更新(Update):在服务器更新数据(所有字段)UPDATE/product/:id
PATCH更新(Update):在服务器更新数据(部分字段)UPDATE/product/:id
DELETE删除(Delete):在服务器删除数据DELETE/product/:id

Headers

规范使用 HTTP Headers,参见 MDN Web Doc

正面例子 👍
POST /api/product
Authorization: Bearer b25ed4f6b1ec69afea62dc248e52b8b24c090dbf3c07046bf8ff8a6b
Content-Type: application/json
反面例子 👎

Headers 不是标准 HTTP Headers

POST /api/product
AuthType: sid
Client: pc_web
UserType: user
UserKey: param:key:loginInfo:zyd0214999218:WECHAT:b46bf79b

安全约定

永远不要信任用户输入,为所有参数进行有效性校验

对于前端,参数有效性校验避免无效的请求,减轻服务器负载,提升用户体验。但是对于后端,参数有效性校验可以有效避免恶意请求,避免无效数据的写入,对数据安全和数据一致性有重大保障。

后端校验永远优选于前端校验,推荐使用 Hibernate Validator 进行后端校验。

敏感字段

敏感字段使用 AES 加密传输,前端/后端均需要做加密/解密处理。

敏感字段包括但不限于:

  • 身份证号码
  • 银行卡号
  • 密码
  • 手机号码
  • 家庭住址
  • 健康数据
注意

密码仅限在请求时作为参数使用,响应参数不应该包含密码相关字段。在数据库,密码字段推荐使用 Bcrypt 算法 或者 PBKDF2 算法进行存储。

正面例子 👍
{
"name": "田野",
"idNumber": "RKGJ2oqWrHUhbV0YggJhCU3lZOD5H3/+vR944hOozl4=",
"password": "5wlvu+Ye7TC33MT3VKxU6neaTpPk5EvfuGs+8a7zRLc="
}
反面例子 👎
{
"name": "田野",
"idNumber": "310000199511159999",
"password": "meiko@xxx.com"
}

对自增 ID 进行 Hash

不要直接使用自增 ID,这会导致爬虫泛滥,并容易泄漏数据量,直接使用自增 ID 还容易引起暴力破解的风险。

推荐对自增 ID 进行 Hash(例如 YouTube 和 bilibili),可以隐藏真实的业务 ID,从而增加了攻击成本。建议参考 Sqids

正面例子 👍
{
"id": "Zn8DxdXx5Z5VD51dwElom"
}
反面例子 👎
{
"id": 1
}

响应

HTTP 状态码

规范使用 HTTP 状态码,参见 MDN Web Doc

Methods状态码
GET200 OK
POST201 Created
PUT200 OK
PATCH200 OK
DELETE204 No Content

成功状态码说明

状态码说明使用场景
200 OK请求成功GETPUTPATCH 请求的响应
201 Created请求已成功,并因此创建了一个新的资源POST 请求的响应
202 Accepted请求已经接收到,但还未响应,没有结果用于高并发量的提交或者修改接口,前端需要长轮询获取真正的请求状态,API 通常需要使用 RabbitMQ 或者 Apache Kafka 等消息队列
204 No Content对于该请求没有响应可发送DELETE 请求的响应

错误状态码说明

状态码说明使用场景
400 Bad Request语义有误,当前请求无法被服务器理解 或者 请求参数有误用于常见逻辑错误,如解析 JSON 出现错误 或者 注册时用户已存在
401 Unauthorized当前请求需要用户验证用户未提供身份验证凭据,或者没有通过身份验证(未登录 或者 登录过期)
403 Forbidden当前请求拒绝访问用户通过了身份验证,但是不具有访问资源所需的权限(已登录,但是没有该接口的访问权限)
404 Not Found当前请求的 URL 不存在API 没有此 URL 地址
405 Method Not Allowed当前请求的方法不被支持如 API 要求 POST,而客户端使用 GET
406 Not Acceptable当前请求要求的返回格式不支持如 API 返回 JSON,而客户端要求 XML
413 Payload Too Large当前请求提交的实体数据大小超过了能够处理的范围比如文件上传过大
414 URI Too Long当前请求的 URI 长度超过了服务器能够解释的长度如 Query String 过长,或者一些安全攻击
415 Unsupported Media Type当前请求发送的实体格式服务端不支持如 API 要求发送 JSON,而客户端发送 FormData
422 Unprocessable Entity语义正确,但是服务器无法处理所包含的指令用于提示表单校验错误信息
429 Too Many Requests在一定的时间内用户发送了太多的请求,即超出了“频次限制”用于限制用户短时间内的请求频率和预防 DDoS
500 Internal Server Error服务器错误,包括了其他 5xx 状态码API 代码运行出现异常并未被正确处理,或者服务器已经宕机

响应格式

  • 应该使用 JSON,避免使用 XML 或 其他数据格式
正面例子 👍
{
"id": "GwW0bZAzm2qQE1wDKqope"
}
反面例子 👎

使用纯文本

GwW0bZAzm2qQE1wDKqope

使用 XML

<product>
<id>GwW0bZAzm2qQE1wDKqope</id>
</product>
备注
Accept: application/json
Content-Type: application/json
  • 前后端传输过程以标准 JSON 格式,避免反复正反序列化
正面例子 👍
{
"data": [
{
"id": "zNBWQ4VrEeMKkmY4PgvaX",
"name": "施耐德 iC65 微型断路器"
},
{
"id": "zKLNwDGMm6qQRegxvBr5A",
"name": "施耐德 EA9AN 微型断路器"
}
]
}
反面例子 👎
{
"data": "[{\"id\": \"zNBWQ4VrEeMKkmY4PgvaX\",\"name\": \"施耐德 iC65 微型断路器\"},{\"id\": \"zKLNwDGMm6qQRegxvBr5A\",\"name\": \"施耐德 EA9AN 微型断路器\"}]"
}
  • 时间字段以 RFC 3339 格式返回:YYYY-MM-DDTHH:MM:SSZ
正面例子 👍
{
"date": "2022-07-03T23:01:36+08:00"
}
反面例子 👎

时间格式不符合 RFC 3339 格式

{
"date": "2022-07-03 23:01:36"
}

使用时间戳

{
"date": 1656860496
}
  • 空数组使用 [],而不是 null
正面例子 👍
{
"list": []
}
反面例子 👎
{
"list": null
}

统一错误响应

在接口处理发生错误的时候,如果是客户端请求参数导致的错误,会返回 4xx 状态码,如果是服务端的处理逻辑错误,会返回 5xx 状态码。所有的异常对象都是对这个异常状态的描述:

{
"code": "A0410",
"message": "用户名不能为空",
"error": "`userName` is required"
}
interface Error {
code: string;
message: string;
error: string;
}
参数说明
code错误编码,详见附录
message错误提示信息,可用于前端界面提示,要求:简短清晰、提示友好,引导用户进行下一步操作或解释错误原因,提示信息可以包括错误原因、上下文环境、推荐操作
error导致错误的详细原因,需要记录进日志,在开发环境协助调试
5xx 服务端错误

对于出现 5xx 服务端错误,可以在开发环境将服务器的错误信息返回,方便在开发中调试:

// 开发环境,可以显示 error,方便调试
{
"code": "A0420",
"message": "请求参数值超出允许的范围",
"error": "Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"4294967295\""
}

但是在生产环境中,绝对不要这么做!避免出现安全问题:

// 生产环境,将 error 信息写入日志,避免在前端界面中显示
{
"code": "A0420",
"message": "请求参数值超出允许的范围",
"error": ""
}

注意:无论报错原因为何,凡是出现 5xx 服务端错误,客户端均不会做任何修改

查询类接口 - GET

MethodsURL说明状态码响应
GET/api/product查询所有数据200 OKObject[]
GET/api/product?keyword=IC65带查询参数,查询数据200 OKObject[]
GET/api/product?page=0&size=20带分页参数,查询数据200 OKPagination
GET/api/product/2AE6RZd9wnmNdv7DLn0bd查询指定详情数据200 OKObject
interface PaginationMeta {
pages: number;
total: number;
}

interface Pagination {
content: Object[];
meta: PaginationMeta;
}

查询参数

查询类接口通常使用 QueryString 作为参数,通常在列表查询中使用

固定查询参数

分页
参数说明示例
page指定第几页,需要与size搭配使用,从 0 开始?page=2&size=100
size指定每页的记录数,需要与page搭配使用,如不传此参数则不分页?page=2&size=100
GET /api/product?page=0&size=100  # 查询第 1 页数据,每页 100 条
GET /api/product?page=2&size=100 # 查询第 3 页数据,每页 100 条
GET /api/product # 查询所有数据
排序
参数说明示例
sortby指定返回结果按照哪个属性排序,需要与order搭配使用?sortby=name&order=asc
order排序顺序,需要与sortby搭配使用?sortby=name&order=asc
GET /api/product?sortby=createdAt&order=asc   # 按 createdAt 字段升序排序
GET /api/product?sortby=updatedAt&order=desc # 按 updatedAt 字段降序排序
限制查询条数
参数说明示例
limit指定返回记录的数量?limit=10
offset指定返回记录的开始位置?offset=10
GET /api/product?limit=10            # 查询 10 条数据
GET /api/product?limit=10&offset=10 # 查询 10 条数据,从第 10 条开始查询
全文搜索
参数说明示例
keyword多列模糊查询,通常与全文搜索引擎(如 ElasticSearch)搭配使用?keyword=IC65
GET /api/product?keyword=IC65  # 查询任意字段中包含 IC65 关键词的数据

非固定查询参数

ID

ID型数据使用精确查询,常用于外联字段,需要支持多个查询,参数命名以Ids结尾

GET /api/product?categoryIds=65     # 查询所有 categoryId 为 65 的数据
GET /api/product?categoryIds=65,97 # 查询所有 categoryId 为 65 或 97 的数据
文本型

文本型数据使用模糊查询参数命名为字段名

GET /api/product?name=IC65  # 查询所有 name 包含 IC65 的数据
枚举

枚举型数据使用精确查询,需要支持多个查询,参数命名为字段名

GET /api/product?status=pending           # 查询所有 status 为 pending 的数据
GET /api/product?status=pending,complete # 查询所有 status 为 pending 或 complete 的数据
数值型

数值型数据,根据情况,使用精确查询区间查询

  • 精确查询参数命名为字段名
  • 区间查询:增加约定前缀
    • gt:大于
    • gte:大于等于
    • lt:小于
    • lte:小于等于
GET /api/product?stock=10                 # 查询所有 stock = 10 的数据

GET /api/product?gtStock=10 # 查询所有 stock > 10 的数据
GET /api/product?gteStock=10 # 查询所有 stock >= 10 的数据
GET /api/product?ltStock=10 # 查询所有 stock < 10 的数据
GET /api/product?lteStock=10 # 查询所有 stock <= 10 的数据

GET /api/product?gtStock=10&ltStock=20 # 查询所有 stock > 10 && stock < 20 的数据
GET /api/product?gteStock=10&lteStock=20 # 查询所有 stock >= 10 && stock <= 20 的数据
时间/日期

时间/日期型字段,使用区间查询,以 beforeafter 作为前缀

# 查询所有 date 在 2022-07-04 13:00 ~ 2022-07-04 13:59 的数据(一小时)
GET /api/product?afterDate=2022-07-04T13:00:00+08:00&beforeDate=2022-07-04T13:59:59+08:00

# 查询所有 date 在 2022-07-04 的数据(一天)
GET /api/product?afterDate=2022-07-04T00:00:00+08:00&beforeDate=2022-07-04T23:59:59+08:00

# 查询所有 date 在 2022-07-03 ~ 2022-07-09 的数据(一周)
GET /api/product?afterDate=2022-07-03T00:00:00+08:00&beforeDate=2022-07-09T23:59:59+08:00

# 查询所有 date 在 2022-07-01 ~ 2022-07-31 的数据(一个月)
GET /api/product?afterDate=2022-07-01T00:00:00+08:00&beforeDate=2022-07-31T23:59:59+08:00

# 查询所有 date 在 2022-07-01 ~ 2022-09-30 的数据(一季度)
GET /api/product?afterDate=2022-07-01T00:00:00+08:00&beforeDate=2022-09-30T23:59:59+08:00

# 查询所有 date 在 2022-01-01 ~ 2022-12-31 的数据(一年)
GET /api/product?afterDate=2022-01-01T00:00:00+08:00&beforeDate=2022-12-31T23:59:59+08:00
提示

建议充分使用 date-fnsstartOfDayendOfDayformatRFC3339 方法,获取当天的开始时间和结束时间,并对参数进行格式化。

import { startOfDay, endOfDay, formatRFC3339 } from 'date-fns';

const startDate = formatRFC3339(startOfDay(form.startDate));
const endDate = formatRFC3339(endOfDay(form.startDate));

fetch(url, {
data: {
afterDate: startDate,
beforeDate: endDate,
},
});

查询类接口响应格式

列表查询(分页)

{
"content": [
{
"id": "PrJ38xvJd5gLwrBxO9Y1A",
"name": "施耐德 iC65 微型断路器",
"stock": 10,
"status": "sale",
"createdAt": "2022-07-04T13:03:06+08:00"
},
{
"id": "V0WJa4X26eygvwLZl9pom",
"name": "施耐德 EA9AN 微型断路器",
"stock": 10,
"status": "inquiry",
"createdAt": "2022-07-04T13:03:06+08:00"
}
],
"meta": {
"pages": 10,
"total": 10086
}
}

列表查询(不分页)

[
{
"id": "PrJ38xvJd5gLwrBxO9Y1A",
"name": "施耐德 iC65 微型断路器",
"stock": 10,
"status": "sale",
"createdAt": "2022-07-04T13:03:06+08:00"
},
{
"id": "V0WJa4X26eygvwLZl9pom",
"name": "施耐德 EA9AN 微型断路器",
"stock": 10,
"status": "inquiry",
"createdAt": "2022-07-04T13:03:06+08:00"
}
]

单条查询

{
"id": "PrJ38xvJd5gLwrBxO9Y1A",
"name": "施耐德 iC65 微型断路器",
"stock": 10,
"status": "sale",
"createdAt": "2022-07-04T13:03:06+08:00"
}

注意事项

所有数组需要返回一个key
正面例子 👍
{
"list": [
{
"id": "OjP9LDwma52gR21x8kzBm",
"name": "施耐德 iC65 微型断路器"
},
{
"id": "JVny0D1v6G8Wqpe4d7XPR",
"name": "施耐德 EA9AN 微型断路器"
}
]
}
反面例子 👎
{
"list": [
{
"name": "施耐德 iC65 微型断路器"
},
{
"name": "施耐德 EA9AN 微型断路器"
}
]
}
可枚举字段使用有语义英文而非无语义数字
正面例子 👍
{
"status": "pending" // "pending" | "complete" | "error"
}
反面例子 👎
{
"status": 0
}
合理自然嵌套结构而不是平铺

对于外联数据,使用自然嵌套结构而不是平铺

正面例子 👍
{
"id": "PrJ38xvJd5gLwrBxO9Y1A",
"name": "施耐德 iC65 微型断路器",
"categoryId": "1qWp840q2nPPy6kxJmyBn",
"category": {
"id": "1qWp840q2nPPy6kxJmyBn",
"name": "微信断路器"
}
}
反面例子 👎
{
"id": "PrJ38xvJd5gLwrBxO9Y1A",
"name": "施耐德 iC65 微型断路器",
"categoryId": "1qWp840q2nPPy6kxJmyBn",
"categoryName": "微信断路器"
}

创建类接口 - POST

请求参数

创建类接口参数使用 JSON 作为请求体,不应该使用 QueryString

正面例子 👍
POST /api/user
Content-Type: application/json

{
"username": "meiko",
"password": "5wlvu+Ye7TC33MT3VKxU6neaTpPk5EvfuGs+8a7zRLc="
}
反面例子 👎
POST /api/user?username=meiko&password=5wlvu%2BYe7TC33MT3VKxU6neaTpPk5EvfuGs%2B8a7zRLc%3D

创建类接口响应

MethodsURL说明状态码响应
POST/api/product创建数据201 CreatedObject

创建完成后直接返回 ID

{
"id": "LjzXJx6k627PQNKZ2lN7B"
}

请求参数约束

关联关系只以 id 为标识,其它字段不应依赖客户端

以创建用户为例:POST /api/users

正面例子 👍
{
"username": "meiko",
"password": "xxxx",
"roleIds": [1, 2, 3]
}
反面例子 👎
{
"username": "meiko",
"password": "xxxx",
"roleIds": [
{
"id": 1,
"name": "角色1"
},
{
"id": 2,
"name": "角色2"
},
{
"id": 3,
"name": "角色3"
}
]
}

更新类接口 - PUT/PATCH

MethodsURL说明状态码响应
PUT/api/product/lkrdQx3Q6zNkRzeDRnv68更新指定数据(所有字段)200 OKObject
PATCH/api/product/lkrdQx3Q6zNkRzeDRnv68更新指定数据(部分字段)200 OKObject

更新完成后直接返回 ID

{
"id": "lkrdQx3Q6zNkRzeDRnv68"
}
提示

总体来说,更新类接口与创建类接口很相似

删除类接口 - DELETE

MethodsURL说明状态码响应
DELETE/api/product/dLEM04mVQavML57x8GV3q删除单条数据204 No Content
DELETE/api/product?ids=dLEM04mVQavML57x8GV3q,W0dpVxlO6dlnQwb4Pav5q批量删除数据204 No Content

删除接口应酌情提供批量删除

例如 DELETE /api/product/1 表示删除 id 为 1 的数据

例如 DELETE /api/product?ids=1,2,3 表示批量删除 id 为 1 或 2 或 3 的数据

文件类接口

统一上传接口

MethodsURL说明状态码响应
POST/api/file上传文件201 CreatedFile
POST/api/multiple-files批量上传文件201 CreatedFile[]
interface File {
id: string;
url: string;
name: string;
}
参数说明
id文件 ID,通常是文件的 checksum
url文件在 CDN 或者 OSS 的 URL
name原文件名
注意

上传接口的参数为 FormData,而非 JSON

POST /api/file
Content-Type: multipart/form-data

单个上传文件

// 请求,注意这里是 FormData
{
file: File
}
// 响应
{
"id": "ef7497affc2eedee5cb6fd58d8a86b310cc8d54a36c2569eb7c296e1af69efd5",
"url": "https://cdn.example.com/upload/991b202e42d50c297d8785a40764e0df.pptx",
"name": "nginx安装和配置指南.pptx"
}

批量上传文件

// 请求,注意这里是 FormData
{
files: [File, File]
}
// 响应
[
{
"id": "ef7497affc2eedee5cb6fd58d8a86b310cc8d54a36c2569eb7c296e1af69efd5",
"url": "https://cdn.example.com/upload/991b202e42d50c297d8785a40764e0df.pptx",
"name": "nginx安装和配置指南.pptx"
},
{
"id": "da0651efdbce6b3cc06b3fb509177e7ab5d4c1b0e93b7a4d72acaad0cdf16152",
"url": "https://cdn.example.com/upload/9fb3f25df4cf34e8fefe17be2d44fddd.pptx",
"name": "前端入职培训.pptx"
}
]

注意事项

  • 对于使用到文件的接口使用文件 id 或地址而非 FormData
正面例子 👍

使用文件ID

{
"name": "施耐德 iC65 微型断路器",
"fileId": "db93274594e9013a4190f068fabdfdbee5e9ccf8c02159439facb3bd51190bd2"
}

使用文件地址

{
"name": "施耐德 iC65 微型断路器",
"fileUrl": "https://cdn.example.com/files/bb313c99.png"
}

注意:先由 POST /api/file 上传完文件拿到文件 id 或地址后再执行后续操作

反面例子 👎
{
name: "施耐德 iC65 微型断路器",
file: File
}

使用文件

  • 文件路径至少补全至根路径
正面例子 👍

补全至根路径

{
"data": {
"id": "6GLj047k6RqKAnR4Qyq2A",
"name": "施耐德 iC65 微型断路器",
"avatar": "/upload/bb313c99.png"
}
}

或者直接使用 CDN 或 OSS

{
"data": {
"id": "6GLj047k6RqKAnR4Qyq2A",
"name": "施耐德 iC65 微型断路器",
"avatar": "https://cdn.example.com/files/bb313c99.png"
}
}
反面例子 👎
{
"data": {
"id": "6GLj047k6RqKAnR4Qyq2A",
"name": "施耐德 iC65 微型断路器",
"avatar": "bb313c99.png"
}
}
  • 使用 CDN 或者 OSS 时,要求使用 HTTPS 协议
正面例子 👍
{
"data": {
"id": "QPXw3DE7r8YaK2gxWm78e",
"name": "施耐德 iC65 微型断路器",
"avatar": "https://cdn.example.com/files/bb313c99.png"
}
}
反面例子 👎
{
"data": {
"id": "QPXw3DE7r8YaK2gxWm78e",
"name": "施耐德 iC65 微型断路器",
"avatar": "http://cdn.example.com/files/bb313c99.png"
}
}
  • 不要使用 CDN 或者 OSS 参数,以便前端灵活处理
正面例子 👍
{
"fileUrl": "https://cdn.example.com/files/bb313c99.png"
}
反面例子 👎
{
"fileUrl": "https://cdn.example.com/files/bb313c99.png?x-oss-process=style/s1"
}

文档

文档推荐使用 OpenAPI Specification

附录:错误码列表

用户端错误

错误码中文描述
A0001用户端错误

用户注册错误

错误码中文描述
A0100用户注册错误
A0101用户未同意隐私协议
A0102注册国家或地区受限
A0110用户名校验失败
A0111用户名已存在
A0112用户名包含敏感词
A0113用户名包含特殊字符
A0120密码校验失败
A0121密码长度不够
A0122密码强度不够
A0130校验码输入错误
A0131短信校验码输入错误
A0132邮件校验码输入错误
A0133语音校验码输入错误
A0140用户证件异常
A0141用户证件类型未选择
A0142大陆身份证编号校验非法
A0143护照编号校验非法
A0144军官证编号校验非法
A0150用户基本信息校验失败
A0151手机格式校验失败
A0152地址格式校验失败
A0153邮箱格式校验失败

用户登录异常

错误码中文描述
A0200用户登录异常
A0201用户账户不存在
A0202用户账户被冻结
A0203用户账户已作废
A0210用户密码错误
A0211用户输入密码错误次数超限
A0220用户身份校验失败
A0221用户指纹识别失败
A0222用户面容识别失败
A0223用户未获得第三方登录授权
A0230用户登录已过期
A0240用户验证码错误
A0241用户验证码尝试次数超限

访问权限异常

错误码中文描述
A0300访问权限异常
A0301访问未授权
A0302正在授权中
A0303用户授权申请被拒绝
A0310因访问对象隐私设置被拦截
A0311授权已过期
A0312无权限使用 API
A0320用户访问被拦截
A0321黑名单用户
A0322账号被冻结
A0323非法 IP 地址
A0324网关访问受限
A0325地域黑名单
A0330服务已欠费
A0340用户签名异常
A0341RSA 签名错误

用户请求参数错误

错误码中文描述
A0400用户请求参数错误
A0401包含非法恶意跳转链接
A0402无效的用户输入
A0410请求必填参数为空
A0411用户订单号为空
A0412订购数量为空
A0413缺少时间戳参数
A0414非法的时间戳参数
A0420请求参数值超出允许的范围
A0421参数格式不匹配
A0422地址不在服务范围
A0423时间不在服务范围
A0424金额超出限制
A0425数量超出限制
A0426请求批量处理总个数超出限制
A0427请求 JSON 解析失败
A0430用户输入内容非法
A0431包含违禁敏感词
A0432图片包含违禁信息
A0433文件侵犯版权
A0440用户操作异常
A0441用户支付超时
A0442确认订单超时
A0443订单已关闭

用户请求服务异常

错误码中文描述
A0500用户请求服务异常
A0501请求次数超出限制
A0502请求并发数超出限制
A0503用户操作请等待
A0504WebSocket 连接异常
A0505WebSocket 连接断开
A0506用户重复请求

用户资源异常

错误码中文描述
A0600用户资源异常
A0601账户余额不足
A0602用户磁盘空间不足
A0603用户内存空间不足
A0604用户 OSS 容量不足
A0605用户配额已用光

用户上传文件异常

错误码中文描述
A0700用户上传文件异常
A0701用户上传文件类型不匹配
A0702用户上传文件太大
A0703用户上传图片太大
A0704用户上传视频太大
A0705用户上传压缩文件太大

用户当前版本异常

错误码中文描述
A0800用户当前版本异常
A0801用户安装版本与系统不匹配
A0802用户安装版本过低
A0803用户安装版本过高
A0804用户安装版本已过期
A0805用户 API 请求版本不匹配
A0806用户 API 请求版本过高
A0807用户 API 请求版本过低

用户隐私未授权

错误码中文描述
A0900用户隐私未授权
A0901用户隐私未签署
A0902用户摄像头未授权
A0903用户相机未授权
A0904用户图片库未授权
A0905用户文件未授权
A0906用户位置信息未授权
A0907用户通讯录未授权

用户设备异常

错误码中文描述说明
A1000用户设备异常二级宏观错误码
A1001用户相机异常
A1002用户麦克风异常
A1003用户听筒异常
A1004用户扬声器异常
A1005用户 GPS 定位异常

系统执行出错

错误码中文描述
B0001系统执行出错

系统执行超时

错误码中文描述
B0100系统执行超时
B0101系统订单处理超时

系统容灾功能被触发

错误码中文描述
B0200系统容灾功能被触发
B0210系统限流
B0220系统功能降级

系统资源异常

错误码中文描述
B0300系统资源异常
B0310系统资源耗尽
B0311系统磁盘空间耗尽
B0312系统内存耗尽
B0313文件句柄耗尽
B0314系统连接池耗尽
B0315系统线程池耗尽
B0320系统资源访问异常
B0321系统读取磁盘文件失败

调用第三方服务出错

错误码中文描述
C0001调用第三方服务出错

中间件服务出错

错误码中文描述
C0100中间件服务出错
C0110RPC 服务出错
C0111RPC 服务未找到
C0112RPC 服务未注册
C0113接口不存在
C0120消息服务出错
C0121消息投递出错
C0122消息消费出错
C0123消息订阅出错
C0124消息分组未查到
C0130缓存服务出错
C0131key 长度超过限制
C0132value 长度超过限制
C0133存储容量已满
C0134不支持的数据格式
C0140配置服务出错
C0150网络资源服务出错
C0151VPN 服务出错
C0152CDN 服务出错
C0153域名解析服务出错
C0154网关服务出错

第三方系统执行超时

错误码中文描述
C0200第三方系统执行超时
C0210RPC 执行超时
C0220消息投递超时
C0230缓存服务超时
C0240配置服务超时
C0250数据库服务超时

数据库服务出错

错误码中文描述
C0300数据库服务出错
C0311表不存在
C0312列不存在
C0321多表关联中存在多个相同名称的列
C0331数据库死锁
C0341主键冲突

第三方容灾系统被触发

错误码中文描述
C0400第三方容灾系统被触发
C0401第三方系统限流
C0402第三方功能降级

通知服务出错

错误码中文描述
C0500通知服务出错
C0501短信提醒服务失败
C0502语音提醒服务失败
C0503邮件提醒服务失败