restful API设计规范
rest是一种软件架构风格,如果你们的接口是rest接口,那么就可被认为你们的的接口是 restful
的,英文名词和形容词的区别。
rest
接口是围绕“资源”展开的,利用HTTP的协议,其实rest本也可以和HTTP无关,但是现在大家普遍的使用rest都是依托于HTTP协议。HTTP 的url即资源。
RFC 3986定义了通用的URI语法:
1
URI = scheme “://” authority “/” path [ “?” query ][ “#” fragment ]
scheme
: 指底层用的协议,如http、https、ftphost
: 服务器的IP地址或者域名port
: 端口,http中默认80path
: 访问资源的路径,就是咱们各种web 框架中定义的route路由query
: 为发送给服务器的参数fragment
: 锚点,定位到页面的资源,锚点为资源id
关于「能愿动词」的使用
为了避免歧义,文档大量使用了「能愿动词
」,对应的解释如下:
- 必须 (MUST):绝对,严格遵循,请照做,无条件遵守;
- 一定不可 (MUST NOT):禁令,严令禁止;
- 应该 (SHOULD) :强烈建议这样做,但是不强求;
- 不该 (SHOULD NOT):强烈不建议这样做,但是不强求;
- 可以 (MAY) 和 可选 (OPTIONAL) :选择性高一点,在这个文档内,此词语使用较少;
Protocol
客户端在通过 API 与后端服务通信的过程中, 应该
使用 HTTPS
协议。
API Root URL
API 的根入口点应尽可能保持足够简单,这里有两个常见的 URL 根例子:
1
2
api.example.com/*
example.com/api/*
如果你的应用很庞大或者你预计它将会变的很庞大,那 应该
将 API 放到子域下(api.example.com
)。这种做法可以保持某些规模化上的灵活性。
Versioning
所有的 API 必须保持向后兼容,你 必须
在引入新版本 API 的同时确保旧版本 API 仍然可用。所以 应该
为其提供版本支持。
目前比较常见的两种版本号形式:
一种是在 URL 中嵌入版本编号 api.example.com/v1/*
这种做法是版本号直观、易于调试;
另一种做法是,将版本号放在 HTTP Header 头中, 通过媒体类型来指定版本信息
1
Accept: application/vnd.example.com.v1+json
其中 vnd
表示 Standards Tree 标准树类型,有三个不同的树: x
,prs
和 vnd
。你使用的标准树需要取决于你开发的项目
- 未注册的树(x)主要表示本地和私有环境
- 私有树(prs)主要表示没有商业发布的项目
- 供应商树(vnd)主要表示公开发布的项目
后面几个参数依次为应用名称(一般为应用域名)、版本号、期望的返回格式。
至于具体把版本号放在什么地方,这个问题一直存在很大的争议,但由于我们大多数时间都在使用 Laravel 开发,应该 使用 dingo/api 来快速构建应用,它采用第二种方式来管理 API 版本,并且已集成了标准的 HTTP Response。
Endpoints
路径又称”终点”(endpoint),表示API的具体网址。
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。
URL中不能有动词
在Restful架构中,每个网址代表的是一种资源,所以网址中不能有动词,只能有名词。
动词由HTTP的 get、post、put、delete 四种方法来表示。
## URL结尾不应该包含斜杠“/”
这是作为URL路径中处理中最重要的规则之一,正斜杠(/
)不会增加语义值,且可能导致混淆。REST API不允许一个尾部的斜杠,不应该将它们包含在提供给客户端的链接的结尾处。
许多Web组件和框架将平等对待以下两个URI:
1
2
http://api.canvas.com/shapes/
http://api.canvas.com/shapes
但是,实际上URI中的每个字符都会计入资源的唯一身份的识别中。
两个不同的URI映射到两个不同的资源。如果URI不同,那么资源也是如此,反之亦然。因此,REST API必须生成和传递精确的URI,不能容忍任何的客户端尝试不精确的资源定位。
有些API碰到这种情况,可能设计为让客户端重定向到相应没有尾斜杠的URI(也有可能会返回301 - 用来资源重定向)。
正斜杠分隔符”/“必须用来指示层级关系
url 的路径中的正斜杠 “/
“ 字符用于指示资源之间的层次关系。
例如:
1
2
3
http://api.user.com/schools/grades/classes/boys - 学校中所有的男生
http://api.college.com/students/3248234/courses - 检索id为3248234的学生学习的所有课程的清单。
应该使用连字符”-“来提高URL的可读性,而不是使用下划线”_”
为了使URL容易让人们理解,请使用连字符 -
字符来提高长路径中名称的可读性。
一些文本查看器为了区分强调URI,常常会在URI下加上下划线。这样下划线 ”_
” 字符可能被文本查看器中默认的下划线部分地遮蔽或完全隐藏。
为避免这种混淆,请使用连字符 ”-
“ 而不是下划线
RL路径中首选小写字母
RFC 3986将URI定义为区分大小写,但 scheme
和 host
components除外。
URL路径名词均为复数
为了保证url格式的一致性,建议使用复数形式。
来看一个反例
1
2
3
4
https://api.example.com/getUs...
https://api.example.com/getusers
https://api.example.com/sv/u
https://api.example.com/cgi-b...
再来看一个正列
1
2
3
4
5
https://api.example.com/zoos
https://api.example.com/animals
https://api.example.com/zoos/{zoo}/animals
https://api.example.com/anima...
https://api.example.com/emplo...
HTTP 动词
对于资源的具体操作类型,由 HTTP 动词表示。常用的 HTTP 动词有下面五个(括号里是对应的 SQL 命令)。
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
- DELETE(DELETE):从服务器删除资源。
还有两个不常用的HTTP动词。
HEAD
:获取资源的元数据。OPTIONS
:获取信息,关于资源的哪些属性是客户端可以改变的。
针对每一个端点来说,下面列出所有可行的 HTTP 动词和端点的组合
请求方法 | URL | 描述 |
---|---|---|
GET | /zoos | 列出所有的动物园(ID和名称,不要太详细) |
POST | /zoos | 新增一个新的动物园 |
GET | /zoos/{zoo} | 获取指定动物园详情 |
PUT | /zoos/{zoo} | 更新指定动物园(整个对象) |
PATCH | /zoos/{zoo} | 更新动物园(部分对象) |
DELETE | /zoos/{zoo} | 删除指定动物园 |
GET | /zoos/{zoo}/animals | 检索指定动物园下的动物列表(ID和名称,不要太详细) |
GET | /employees | 检索整个雇员列表 |
超出 Restful 端点的, 应该
模仿上表的方式来定义端点。
Filtering
如果记录数量很多,服务器不可能都将它们返回给用户。API 应该
提供参数,过滤返回结果。下面是一些常见的参数。
?limit=10
:指定返回记录的数量?offset=10
:指定返回记录的开始位置。?page=2&per_page=100
:指定第几页,以及每页的记录数。?sortby=name&order=asc
:指定返回结果按照哪个属性排序,以及排序顺序。?animal_type_id=1
:指定筛选条件
参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals
与 GET /animals?zoo_id=ID
的含义是相同的。
所有 URL 参数 必须
是全小写, 必须
使用下划线类型的参数形式。
分页参数 必须
固定为 page
、per_page
经常使用的、复杂的查询 应该
标签化,降低维护成本。如
1
GET /trades?status=closed&sort=sortby=name&order=asc
可为其定制快捷方式
1
GET /trades/recently_closed
Authentication
应该 使用 OAuth2.0 的方式为 API 调用者提供登录认证。 必须
先通过登录接口获取 Access Token 后再通过该 token 调用需要身份认证的 API。
Oauth 的端点设计示列
1
2
3
4
5
6
RFC 6749 /token
Twitter /oauth2/token
Fackbook /oauth/access_token
Google /o/oauth2/token
Github /login/oauth/access_token
Instagram /oauth/authorize
客户端在获得 access token 的同时 必须 在响应中包含一个名为 expires_in
的数据,它表示当前获得的 token 会在多少秒后失效。
1
2
3
4
5
{
"access_token": "token....",
"token_type": "Bearer",
"expires_in": 3600
}
客户端在请求需要认证的 API 时, 必须
在请求头 Authorization
中带上 access_token
。
1
Authorization: Bearer token...
当超过指定的秒数后,access token
就会过期,再次用过期/或无效的 token
访问时,服务端 应该
返回 invalid_token
的错误或 401
错误码。
1
2
3
4
5
6
7
8
HTTP/1.1 401 Unauthorized
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"error": "invalid_token"
}
Laravel 开发中,应该 使用 JWT 来为管理你的 Token,并且 一定不可
在 api 中间件中开启请求 session。
Response
所有的 API 响应, 必须
遵守 HTTP 设计规范, 必须
选择合适的 HTTP 状态码。 一定不可
所有接口都返回状态码为 200
的 HTTP 响应,如:
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
"code": 0,
"msg": "success",
"data": {
"username": "username"
}
}
或
1
2
3
4
5
6
7
8
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
"code": -1,
"msg": "该活动不存在",
}
下表列举了常见的 HTTP 状态码
状态码 | 描述 |
---|---|
1xx | 代表请求已被接受,需要继续处理 |
2xx | 请求已成功,请求所希望的响应头或数据体将随此响应返回 |
3xx | 重定向 |
4xx | 客户端原因引起的错误 |
5xx | 服务端原因引起的错误 |
只有来自客户端的请求被正确的处理后才能返回 2xx
的响应,所以当 API 返回 2xx
类型的状态码时,前端 必须
认定该请求已处理成功。
必须强调的是,所有 API 一定不可
返回 1xx
类型的状态码。当 API 发生错误时, 必须
返回出错时的详细信息。目前常见返回错误信息的方法有两种:
- 将错误详细放入 HTTP 响应首部;
1 2 3
X-MYNAME-ERROR-CODE: 4001 X-MYNAME-ERROR-MESSAGE: Bad authentication token X-MYNAME-ERROR-INFO: http://docs.example.com/api/v1/authentication
- 直接放入响应实体中;
1 2 3 4 5 6 7 8 9
HTTP/1.1 401 Unauthorized Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 10:02:59 GMT Connection: keep-alive {"error_code":40100,"message":"Unauthorized"}
考虑到易读性和客户端的易处理性,我们
必须
把错误信息直接放到响应实体中,并且错误格式应该
满足如下格式:
1
2
3
4
{
"message": "您查找的资源不存在",
"error_code": 404001
}
其中错误码( error_code
)必须 和 HTTP 状态码对应,也方便错误码归类,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 429 Too Many Requests
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:15:52 GMT
Connection: keep-alive
{"error_code":429001,"message":"你操作太频繁了"}
HTTP/1.1 403 Forbidden
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:19:27 GMT
Connection: keep-alive
{"error_code":403002,"message":"用户已禁用"}
应该
在返回的错误信息中,同时包含面向开发者和面向用户的提示信息,前者可方便开发人员调试,后者可直接展示给终端用户查看如:
1
2
3
4
5
6
7
8
{
"message": "直接展示给终端用户的错误信息",
"error_code": "业务错误码",
"error": "供开发者查看的错误信息",
"debug": [
"错误堆栈,必须开启 debug 才存在"
]
}
状态码
下面详细列举了各种情况 API 的返回说明。
200 ok
200
状态码是最常见的 HTTP 状态码,在所有 成功 的 GET 请求中, 必须
返回此状态码。HTTP 响应实体部分 必须
直接就是数据,不要做多余的包装。
错误示例:
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
"user": {
"id":1,
"nickname":"fwest",
"username": "example"
}
}
正确示例:
1、获取单个资源详情
1
2
3
4
5
{
"id": 1,
"username": "godruoyi",
"age": 88,
}
2、获取资源集合
1
2
3
4
5
6
7
8
9
10
11
12
[
{
"id": 1,
"username": "godruoyi",
"age": 88,
},
{
"id": 2,
"username": "foo",
"age": 88,
}
]
3、额外的媒体信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"data": [
{
"id": 1,
"avatar": "https://lorempixel.com/640/480/?32556",
"nickname": "fwest",
"last_logined_time": "2018-05-29 04:56:43",
"has_registed": true
},
{
"id": 2,
"avatar": "https://lorempixel.com/640/480/?86144",
"nickname": "zschowalter",
"last_logined_time": "2018-06-16 15:18:34",
"has_registed": true
}
],
"meta": {
"pagination": {
"total": 101,
"count": 2,
"per_page": 2,
"current_page": 1,
"total_pages": 51,
"links": {
"next": "http://api.example.com?page=2"
}
}
}
}
其中,分页和其他额外的媒体信息,必须放到 meta
字段中。
201 Created
当服务器创建数据成功时, 应该
返回此状态码。常见的应用场景是使用 POST 提交用户信息,如:
- 添加了新用户
- 上传了图片
- 创建了新活动
等,都可以返回 201
状态码。需要注意的是,你可以选择在用户创建成功后返回新用户的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 201 Created
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:13:40 GMT
Connection: keep-alive
{
"id": 1,
"avatar": "https:\/\/lorempixel.com\/640\/480\/?32556",
"nickname": "fwest",
"last_logined_time": "2018-05-29 04:56:43",
"created_at": "2018-06-16 17:55:55",
"updated_at": "2018-06-16 17:55:55"
}
也可以返回一个响应实体为空的 HTTP Response 如:
1
2
3
4
5
6
HTTP/1.1 201 Created
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:12:20 GMT
Connection: keep-alive
这里我们 应该
采用第二种方式,因为大多数情况下,客户端只需要知道该请求操作成功与否,并不需要返回新资源的信息。
202 Accepted
该状态码表示服务器已经接受到了来自客户端的请求,但还未开始处理。常用短信发送、邮件通知、模板消息推送等这类很耗时需要队列支持的场景中;
返回该状态码时,响应实体 必须
为空。
1
2
3
4
5
6
7
HTTP/1.1 202 Accepted
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:25:15 GMT
Connection: keep-alive
204 No Content
该状态码表示响应实体不包含任何数据,其中:
在使用 DELETE
方法删除资源 成功 时, 必须
返回该状态码
使用 PUT、PATCH
方法更新数据 成功 时,也 应该
返回此状态码
1
2
3
4
HTTP/1.1 204 No Content
Server: nginx/1.11.9
Date: Sun, 24 Jun 2018 09:29:12 GMT
Connection: keep-alive
3xx 重定向
所有 API 不该
返回 3xx
类型的状态码。因为 3xx
类型的响应格式一般为下列格式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HTTP/1.1 302 Found
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 09:41:50 GMT
Location: https://example.com
Connection: keep-alive
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url=https://example.com" />
<title>Redirecting to https://example.com</title>
</head>
<body>
Redirecting to <a href="https://example.com">https://example.com</a>.
</body>
</html>
所有 API 一定不可
返回纯 HTML 结构的响应;若一定要使用重定向功能,可以 返回一个响应实体为空的 3xx
响应,并在响应头中加上 Location
字段:
1
2
3
4
5
6
7
HTTP/1.1 302 Found
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:52:50 GMT
Location: https://godruoyi.com
Connection: keep-alive
400 Bad Request
由于明显的客户端错误(例如,请求语法格式错误、无效的请求、无效的签名等),服务器 应该
放弃该请求。
当服务器无法从其他 4xx
类型的状态码中找出合适的来表示错误类型时,都 必须
返回该状态码。
1
2
3
4
5
6
7
8
9
HTTP/1.1 400 Bad Request
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 13:22:36 GMT
Connection: keep-alive
{"error_code":40000,"message":"无效的签名"}
401 Unauthorized
该状态码表示当前请求需要身份认证,以下情况都 必须
返回该状态码。
- 未认证用户访问需要认证的 API
- access_token 无效/过期
- 客户端在收到 401 响应后,都 应该 提示用户进行下一步的登录操作。
1
2
3
4
5
6
7
8
9
10
HTTP/1.1 401 Unauthorized
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
WWW-Authenticate: JWTAuth
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 13:17:02 GMT
Connection: keep-alive
{"message":"Token Signature could not be verified.","error_code": "40100"}
403 Forbidden
该状态码可以简单的理解为没有权限访问该请求,服务器收到请求但拒绝提供服务。
如当普通用户请求操作管理员用户时, 必须
返回该状态码。
1
2
3
4
5
6
7
8
9
HTTP/1.1 403 Forbidden
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 13:05:34 GMT
Connection: keep-alive
{"error_code":40301,"message":"权限不足"}
404 Not Found
该状态码表示用户请求的资源不存在,如
- 获取不存在的用户信息 (
get /users/9999999
) - 访问不存在的端点
都 必须
返回该状态码,若该资源已永久不存在,则 应该
返回 410
响应。
405 Method Not Allowed
当客户端使用的 HTTP 请求方法不被服务器允许时, 必须
返回该状态码。
如客户端调用了 POST
方法来访问只支持 GET
方法的 API
该响应 必须
返回一个 Allow
头信息用以表示出当前资源能够接受的请求方法的列表。
1
2
3
4
5
6
7
8
9
10
HTTP/1.1 405 Method Not Allowed
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Allow: GET, HEAD
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 12:30:57 GMT
Connection: keep-alive
{"message":"405 Method Not Allowed","error_code": 40500}
406 Not Acceptable
API 在不支持客户端指定的数据格式时,应该返回此状态码。如支持 JSON
和 XML
输出的 API 被指定返回 YAML
格式的数据时。
Http 协议一般通过请求首部的 Accept
来指定数据格式
408 Request Timeout
客户端请求超时时 必须
返回该状态码,需要注意的时,该状态码表示客户端请求超时,在涉及第三方 API 调用超时时,一定不可
返回该状态码。
409 Confilct
该状态码表示因为请求存在冲突无法处理。如通过手机号码提供注册功能的 API,当用户提交的手机号已存在时, 必须
返回此状态码。
1
2
3
4
5
6
7
8
9
HTTP/1.1 409 Conflict
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 12:19:04 GMT
Connection: keep-alive
{"error_code":40900,"message":"手机号已存在"}
410 Gone
和 404
类似,该状态码也表示请求的资源不存在,只是 410
状态码进一步表示所请求的资源已不存在,并且未来也不会存在。在收到 410
状态码后,客户端 应该
停止再次请求该资源。
413 Request Entity Too Large
该状态码表示服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。
此种情况下,服务器可以关闭连接以免客户端继续发送此请求。
如果这个状况是临时的,服务器 应该
返回一个 Retry-After
的响应头,以告知客户端可以在多少时间以后重新尝试。
414 Request-URI Too Long
该状态码表示请求的 URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。
415 Unsupported Media Type
通常表示服务器不支持客户端请求首部 Content-Type
指定的数据格式。如在只接受 JSON
格式的 API 中放入 XML
类型的数据并向服务器发送,都 应该
返回该状态码。
该状态码也可用于如:只允许上传图片格式的文件,但是客户端提交媒体文件非法或不是图片类型,这时 应该
返回该状态码:
1
2
3
4
5
6
7
8
9
HTTP/1.1 415 Unsupported Media Type
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 12:09:40 GMT
Connection: keep-alive
{"error_code":41500,"message":"不允许上传的图片格式"}
429 Too Many Requests
该状态码表示用户请求次数超过允许范围。如 API 设定为 60次/分钟,当用户在一分钟内请求次数超过 60 次后,都 应该
返回该状态码。并且也 应该
在响应首部中加上下列头部:
1
2
3
4
X-RateLimit-Limit: 10 请求速率(由应用设定,其单位一般为小时/分钟等,这里是 10次/5分钟)
X-RateLimit-Remaining: 0 当前剩余的请求数量
X-RateLimit-Reset: 1529839462 重置时间
Retry-After: 120 下一次访问应该等待的时间(秒)
比如
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 429 Too Many Requests
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1529839462
Retry-After: 290
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 11:19:32 GMT
Connection: keep-alive
{"message":"You have exceeded your rate limit.","error_code":42900}
必须 为所有的 API 设置 Rate Limit
支持。
500 Internal Server Error
该状态码 必须
在服务器出错时抛出,对于所有的 500
错误,都 应该
提供完整的错误信息支持,也方便跟踪调试。
503 Service Unavailable
该状态码表示服务器暂时处理不可用状态,当服务器需要维护或第三方 API 请求超时/不可达时,都 应该
返回该状态码,其中若是主动关闭 API 服务, 应该
在返回的响应首部加上 Retry-After
头部,表示多少秒后可以再次访问。
1
2
3
4
5
6
7
8
9
10
HTTP/1.1 503 Service Unavailable
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:56:20 GMT
Retry-After: 60
Connection: keep-alive
{"error_code":50300,"message":"服务维护中"}
其他 HTTP 状态码请参考 HTTP 状态码- 维基百科。