2025年4月5日 星期六 乙巳(蛇)年 正月初六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 服务器 > 网络服务

HTTP 接口设计指北

时间:12-14来源:作者:点击数:7

文档主要目的是为大家在设计接口时提供建议,给大家参考 HTTP 或者其他协议/指南已经设计过的内容

只是建议,不是必须遵从的要求

HTTP 协议

HTTP/1.1

2014 年 6 月的时候 IETF 已经正式的废弃了 RFC 2616 ,将它拆分为六个单独的协议说明,并重点对原来语义模糊的部分进行了解释:

相关资料:

  • RFC2616 is Dead(link:https://www.mnot.net/blog/2014/06/07/rfc2616_is_dead) (中文版(link:http://www.infoq.com/cn/news/2014/06/http-11-updated))

HTTP/2

HTTP 协议的 2.0 版本还没有正式发布,但目前已经基本稳定下来了。

2.0 版本的设计目标是尽量在使用层面上保持与 1.1 版本的兼容,所以,虽然数据交换的格式发生了变化,但语义基本全部被保留下来了

因此,作为使用者而言,我们并不需要为了支持 2.0 而大幅修改代码。

URL

URL 的设计都需要遵守 RFC 3986 的的规范。

URL 的长度,在 HTTP/1.1: Message Syntax and Routing(RFC 7230) 的 3.1.1 小节中有说明,本身不限制长度。但是在实践中,服务器和客户端本身会施加限制*,因此需要根据自己的场景和需求做对应的调整

强烈建议 API 部署 SSL 证书,这样接口传递的数据的安全性才能获得一定的保障。

空字段

接口遵循“输入宽容,输出严格”原则,输出的数据结构中空字段的值一律为 null

国际化

语言标签

RFC 5646 (BCP 47) 规定的语言标签的格式如下:

  • language-script-region-variant-extension-privateuse
  1. language:这部分使用的是 ISO 639-1, ISO 639-2, ISO 639-3, ISO 639-5 中定义的语言代码,必填
    • 这个部分由 primary-extlang 两个部分构成
    • primary 部分使用 ISO 639-1, ISO 639-2, ISO 639-3, ISO 639-5 中定义的语言代码,优先使用 ISO 639-1 中定义的条目,比如汉语 zh
    • extlang 部分是在某些历史性的兼容性的原因,在需要非常细致地区别 primary 语言的时候使用,使用 ISO 639-3 中定义的三个字母的代码,比如普通话 cmn
    • 虽然 language 可以只写 extlang 省略 primary 部分,但出于兼容性的考虑,还是建议加上 primary 部分
  2. script: 这部分使用的是 ISO 15924 (Wikipedia) 中定义的语言代码,比如简体汉字是 zh-Hans ,繁体汉字是 zh-Hant 。
  3. region: 这部分使用的是 ISO 3166-1 (Wikipedia) 中定义的地理区域代码,比如 zh-Hans-CN 就是中国大陆使用的简体中文。
  4. variant: 用来表示 extlang 的定义里没有包含的方言,具体的使用方法可以参考 RFC 5646 。
  5. extension: 用来为自己的应用做一些语言上的额外的扩展,具体的使用方法可以参考 RFC 5646 。
  6. privateuse: 用来表示私有协议中约定的一些语言上的区别,具体的使用方法可以参考 RFC 5646 。

其中只有 language 部分是必须的,其他部分都是可选的;不过为了便于编写程序,建议设计接口时约定语言标签的结构,比如统一使用 language-script-region 的形式( zh-Hans-CNzh-Hant-HK 等等)。

语言标签是大小写不敏感的,但按照惯例,建议 script 部分首字母大写, region 部分全部大写,其余部分全部小写。

有一点需要注意,任何合法的标签都必须经过 IANA 的认证,已通过认证的标签可以在这个网页查到。此外,网上还有一个非官方的标签搜索引擎

相关资料:

时区

客户端请求服务器时,如果对时间有特殊要求(如某段时间每天的统计信息),则可以参考 IETF 相关草案 增加请求头 Timezone 。

  • Timezone: 2016-11-06 23:55:52+08:00;;Asia/Shanghai

具体格式说明:

  • Timezone: RFC3339 约定的时间格式;POSIX 1003.1 约定的时区字符串;tz datebase 里的时区名称

客户端最好提供所有字段,如果没有办法提供,则应该使用空字符串

如果客户端请求时没有指定相应的时区,则服务端默认使用最后一次已知时区或者 UTC 时间返回相应数据。

PS 考虑到存在夏时制这种东西,所以不推荐客户端在请求时使用 Offset 。

相关资料:

时间格式

时间格式遵循 ISO 8601(Wikipedia) 建议的格式:

  • 日期 2014-07-09
  • 时间 14:31:22+0800
  • 具体时间 2007-11-06T16:34:41Z
  • 持续时间 P1Y3M5DT6H7M30S (表示在一年三个月五天六小时七分三十秒内)
  • 时间区间 2007-03-01T13:00:00Z/2008-05-11T15:30:00Z 、 2007-03-01T13:00:00Z/P1Y2M10DT2H30M 、 P1Y2M10DT2H30M/2008-05-11T15:30:00Z
  • 重复时间 R3/2004-05-06T13:00:00+08/P0Y6M5DT3H0M0S (表示从2004年5月6日北京时间下午1点起,在半年零5天3小时内,重复3次)

相关资料:

货币名称

货币名称可以参考 ISO 4217(Wikipedia) 中的约定,标准为货币名称规定了三个字母的货币代码,其中的前两个字母是 ISO 3166-1(Wikipedia) 中定义的双字母国家代码,第三个字母通常是货币的首字母。在货币上使用这些代码消除了货币名称(比如 dollar )或符号(比如 $ )的歧义。

相关资料:

  • 《RESTful Web Services Cookbook 中文版》 3.9 节《如何在表述中使用可移植的数据格式》

请求方法

  • 如果请求头中存在 X-HTTP-Method-Override 或参数中存在 _method(拥有更高权重),且值为 GETPOSTPUTDELETEPATCHOPTIONSHEAD 之一,则视作相应的请求方式进行处理
  • GETDELETEHEAD 方法,参数风格为标准的 GET 风格的参数,如 url?a=1&b=2
  • POSTPUTPATCHOPTIONS 方法
    • 默认情况下请求实体会被视作标准 json 字符串进行处理,当然,依旧推荐设置头信息的 Content-Type 为 application/json
    • 在一些特殊接口中(会在文档中说明),可能允许 Content-Type 为 application/x-www-form-urlencoded 或者 multipart/form-data ,此时请求实体会被视作标准 POST 风格的参数进行处理

关于方法语义的说明:

  • OPTIONS 用于获取资源支持的所有 HTTP 方法
  • HEAD 用于只获取请求某个资源返回的头信息
  • GET 用于从服务器获取某个资源的信息
    • 完成请求后返回状态码 200 OK
    • 完成请求后需要返回被请求的资源详细信息
  • POST 用于创建新资源
    • 创建完成后返回状态码 201 Created
    • 完成请求后需要返回被创建的资源详细信息
  • PUT 用于完整的替换资源或者创建指定身份的资源,比如创建 id 为 123 的某个资源
    • 如果是创建了资源,则返回 201 Created
    • 如果是替换了资源,则返回 200 OK
    • 完成请求后需要返回被修改的资源详细信息
  • PATCH 用于局部更新资源
    • 完成请求后返回状态码 200 OK
    • 完成请求后需要返回被修改的资源详细信息
  • DELETE 用于删除某个资源
    • 完成请求后返回状态码 204 No Content

相关资料:

状态码

请求成功

  • 200 OK : 请求执行成功并返回相应数据,如 GET 成功
  • 201 Created : 对象创建成功并返回相应资源数据,如 POST 成功;创建完成后响应头中应该携带头标 Location ,指向新建资源的地址
  • 202 Accepted : 接受请求,但无法立即完成创建行为,比如其中涉及到一个需要花费若干小时才能完成的任务。返回的实体中应该包含当前状态的信息,以及指向处理状态监视器或状态预测的指针,以便客户端能够获取最新状态。
  • 204 No Content : 请求执行成功,不返回相应资源数据,如 PATCH , DELETE 成功

重定向

重定向的新地址都需要在响应头 Location 中返回

  • 301 Moved Permanently : 被请求的资源已永久移动到新位置
  • 302 Found : 请求的资源现在临时从不同的 URI 响应请求
  • 303 See Other : 对应当前请求的响应可以在另一个 URI 上被找到,客户端应该使用 GET 方法进行请求。比如在创建已经被创建的资源时,可以返回 303
  • 307 Temporary Redirect : 对应当前请求的响应可以在另一个 URI 上被找到,客户端应该保持原有的请求方法进行请求

条件请求

  • 304 Not Modified : 资源自从上次请求后没有再次发生变化,主要使用场景在于实现数据缓存
  • 409 Conflict : 请求操作和资源的当前状态存在冲突。主要使用场景在于实现并发控制
  • 412 Precondition Failed : 服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。主要使用场景在于实现并发控制

客户端错误

  • 400 Bad Request : 请求体包含语法错误
  • 401 Unauthorized : 需要验证用户身份,如果服务器就算是身份验证后也不允许客户访问资源,应该响应 403 Forbidden 。如果请求里有 Authorization 头,那么必须返回一个 WWW-Authenticate 头
  • 403 Forbidden : 服务器拒绝执行
  • 404 Not Found : 找不到目标资源
  • 405 Method Not Allowed : 不允许执行目标方法,响应中应该带有 Allow 头,内容为对该资源有效的 HTTP 方法
  • 406 Not Acceptable : 服务器不支持客户端请求的内容格式,但响应里会包含服务端能够给出的格式的数据,并在 Content-Type 中声明格式名称
  • 410 Gone : 被请求的资源已被删除,只有在确定了这种情况是永久性的时候才可以使用,否则建议使用 404 Not Found
  • 413 Payload Too Large : POST 或者 PUT 请求的消息实体过大
  • 415 Unsupported Media Type : 服务器不支持请求中提交的数据的格式
  • 422 Unprocessable Entity : 请求格式正确,但是由于含有语义错误,无法响应
  • 428 Precondition Required : 要求先决条件,如果想要请求能成功必须满足一些预设的条件

服务端错误

  • 500 Internal Server Error : 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。
  • 501 Not Implemented : 服务器不支持当前请求所需要的某个功能。
  • 502 Bad Gateway : 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
  • 503 Service Unavailable : 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间(内容可以为数字,单位为秒;或者是一个 HTTP 协议指定的时间格式)。如果没有给出这个 Retry-After 信息,那么客户端应当以处理 500 响应的方式处理它。

501 与 405 的区别是:405 是表示服务端不允许客户端这么做,501 是表示客户端或许可以这么做,但服务端还没有实现这个功能

相关资料:

身份验证

部分接口需要通过某种身份验证方式才能请求成功(这些接口应该在文档中标注出来),合适的身份验证解决方案目前有两种:

  • HTTP 基本认证最好只在部署了 SSL 证书的情况下才可以使用,否则用户密码会有暴露的风险
  • OAuth 2.0
    • 官网(link:http://oauth.net/2/)
    • 理解OAuth 2.0 - 阮一峰(link:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html) 以及对文中 state 参数的介绍的修正(link:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html#comment-323002)
    • JSON Web Token ,一种 Token 的生成标准
      • Json Web Tokens: Introduction(link:http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/)
      • Json Web Tokens: Examples(link:http://angular-tips.com/blog/2014/05/json-web-tokens-examples/)

超文本驱动和资源发现

REST 服务的要求之一就是超文本驱动(link:http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven),客户端不再需要将某些接口的 URI 硬编码在代码中,唯一需要存储的只是 API 的 HOST 地址,能够非常有效的降低客户端与服务端之间的耦合,服务端对 URI 的任何改动都不会影响到客户端的稳定。

目前有几种方案试图实现这个效果:

  • JSON HAL ,示例可以参考 JSON HAL 作者自己的介绍(link:http://stateless.co/hal_specification.html)
  • GitHub API 使用的方案 ,应该是一种 JSON HAL 的变体
  • JSON API ,(这里有 @迷渡 发起的 中文版(link:http://jsonapi.org.cn/) ),另外一种类似 JSON HAL 的方案
  • Micro API(link:http://micro-api.org/) ,一种试图与 JSON-LD(link:http://json-ld.org/) 兼容的方案

目前所知的方案都实现了发现资源的功能,服务端同时需要实现 OPTIONS 方法,并在响应中携带 Allow 头来告知客户端当前拥有的操作权限。

数据缓存

大部分接口应该在响应头中携带 Last-ModifiedETagVaryDate 信息,客户端可以在随后请求这些资源的时候,在请求头中使用 If-Modified-SinceIf-None-Match 等请求头来确认资源是否经过修改。

如果资源没有进行过修改,那么就可以响应 304 Not Modified 并且不在响应实体中返回任何内容。

  • $ curl -i http://api.example.com/#{RESOURCE_URI}
  • HTTP/1.1 200 OK
  • Cache-Control: public, max-age=60
  • Date: Thu, 05 Jul 2012 15:31:30 GMT
  • Vary: Accept, Authorization
  • ETag: "644b5b0155e6404a9cc4bd9d8b1ae730"
  • Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT
  • Content
  • $ curl -i http://api.example.com/#{RESOURCE_URI} -H "If-Modified-Since: Thu, 05 Jul 2012 15:31:30 GMT"
  • HTTP/1.1 304 Not Modified
  • Cache-Control: public, max-age=60
  • Date: Thu, 05 Jul 2012 15:31:45 GMT
  • Vary: Accept, Authorization
  • Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT
  • $ curl -i http://api.example.com/#{RESOURCE_URI} -H 'If-None-Match: "644b5b0155e6404a9cc4bd9d8b1ae730"'
  • HTTP/1.1 304 Not Modified
  • Cache-Control: public, max-age=60
  • Date: Thu, 05 Jul 2012 15:31:55 GMT
  • Vary: Accept, Authorization
  • ETag: "644b5b0155e6404a9cc4bd9d8b1ae730"
  • Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT

相关资料:

并发控制

不严谨的实现,或者缺少并发控制的 PUT 和 PATCH 请求可能导致 “更新丢失”。这个时候可以使用 Last-Modified 和/或 ETag 头来实现条件请求,支持乐观并发控制。

下文只考虑使用 PUT 和 PATCH 方法更新资源的情况。

  • 客户端发起的请求如果没有包含 If-Unmodified-Since 或者 If-Match 头,那就返回状态码 403 Forbidden ,在响应正文中解释为何返回该状态码
  • 客户端发起的请求提供的 If-Unmodified-Since 或者 If-Match 头与服务器记录的实际修改时间或 ETag 值不匹配的时候,返回状态码 412 Precondition Failed
  • 客户端发起的请求提供的 If-Unmodified-Since 或者 If-Match 头与服务器记录的实际修改时间或 ETag 的历史值匹配,但资源已经被修改过的时候,返回状态码 409 Conflict
  • 客户端发起的请求提供的条件符合实际值,那就更新资源,响应 200 OK 或者 204 No Content ,并且包含更新过的 Last-Modified 和/或 ETag 头,同时包含 Content-Location 头,其值为更新后的资源 URI

相关资料:

  • 《RESTful Web Services Cookbook 中文版》 10.4 节 《如何在服务器端实现条件 PUT 请求》
  • RFC 7232 "Conditional Requests"
  • Location vs. Content-Location(link:https://www.subbu.org/blog/2008/10/location-vs-content-location)

跨域

CORS

接口支持“跨域资源共享”(Cross Origin Resource Sharing, CORS)(link:http://www.w3.org/TR/cors),这里这里这份中文资料(link:http://newhtml.net/using-cors/)有一些指导性的资料。

简单示例:

  • $ curl -i https://api.example.com -H "Origin: http://example.com"
  • HTTP/1.1 302 Found
  • $ curl -i https://api.example.com -H "Origin: http://example.com"
  • HTTP/1.1 302 Found
  • Access-Control-Allow-Origin: *
  • Access-Control-Expose-Headers: ETag, Link, X-Total-Count
  • Access-Control-Allow-Credentials: true

预检请求的响应示例:

  • $ curl -i https://api.example.com -H "Origin: http://example.com" -X OPTIONS
  • HTTP/1.1 302 Found
  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With
  • Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE
  • Access-Control-Expose-Headers: ETag, Link, X-Total-Count
  • Access-Control-Max-Age: 86400
  • Access-Control-Allow-Credentials: true

JSON-P

如果在任何 GET 请求中带有参数 callback ,且值为非空字符串,那么接口将返回如下格式的数据

  • $ curl http://api.example.com/#{RESOURCE_URI}?callback=foo
  • foo({
  • "meta": {
  • "status": 200,
  • "X-Total-Count": 542,
  • "Link": [
  • {"href": "http://api.example.com/#{RESOURCE_URI}?cursor=0&count=100", "rel": "first"},
  • {"href": "http://api.example.com/#{RESOURCE_URI}?cursor=90&count=100", "rel": "prev"},
  • {"href": "http://api.example.com/#{RESOURCE_URI}?cursor=120&count=100", "rel": "next"},
  • {"href": "http://api.example.com/#{RESOURCE_URI}?cursor=200&count=100", "rel": "last"}
  • ]
  • },
  • "data": // data
  • })

其他资料

其他接口设计指南

这里还有一些其他参考资料:

扩充巴科斯范式 (ABNF)

这算是阅读规范的预备知识吧,但写在 README 里还是太占空间了,所以写在了这里。

规范里类似:

  • header-field = field-name ":" OWS field-value OWS
  • field-name = token
  • field-value = *( field-content / obs-fold )
  • field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
  • field-vchar = VCHAR / obs-text
  • obs-fold = CRLF 1*( SP / HTAB )
  • ; obsolete line folding
  • ; see Section 3.2.4

格式的内容叫做“扩充巴科斯范式”,是由 RFC 5234 (Wikipedia) 定义用以描述一些内容的详细格式的定义语言。

User-Agent

请求头中的 User-Agent 可以帮助服务端收集设备信息,但格式需要遵循 RFC 7231 中的定义,下文是一些建议格式:

  • iOS
    • iOS/iOS版本号 (设备型号; 是否越狱<unjailbroken, jailbroken>; 网络类型<Wi-Fi, Cellular, Unknown>; 语言) CFBundleIdentifier/CFBundleVersion
  • Android
    • Android/Android版本号 (设备型号; ROM版本号; 是否root<unrooted, rooted>; 网络类型; 语言) PackageName/PackageVersion
  • Web 应用的 User-Agent 由浏览器设定

示例:

  • User-Agent: iOS/6.1.2 (iPhone 5; jailbroken; Wi-Fi; zh-CN) com.bundle.id/3.2
  • User-Agent: Android/4.2 (MI-ONE Plus; MIUI-2.3.6f; unrooted; GPRS; zh-TW) com.bundle.id/2.1

Android 的网络类型获取可以参考文档:http://developer.android.com/reference/android/telephony/TelephonyManager.html

WWW-Authenticate 头

如果是自定义的身份验证方式,比如要求请求时带上请求头 Authentication: Token <token>,那么一般在 token 验证失败返回 401 的 WWW-Authenticate 头可以是 WWW-Authenticate: Token ,当然也可以带上任意其他自定义信息。客户端在发现自己无法识别的信息时应该略过。

两步验证

如果只是打算简单实现,建议使用 TOTP(Wikipedia) 协议,可以兼容 Google Authenticator 。

关于如何在 API 中实现对两步验证的支持,可以参考 GitHub 的文档

相关资料:

  • 这里是一份 TOTP 协议中密码生成算法的简单说明:http://jacob.jkrall.net/totp/(link:http://jacob.jkrall.net/totp/)
  • What are the advantages of TOTP over HOTP?(link:http://crypto.stackexchange.com/questions/2220/what-are-the-advantages-of-totp-over-hotp)

同时操作多个资源

创建多个相同的资源

请求:

  • POST /resources HTTP/1.1
  • [{
  • "id": "1 也允许由客户端直接指定 ID ,比如 UUID",
  • "name": "resource1",
  • "property": "a"
  • }, {
  • "name": "resource2",
  • "property": "b"
  • }, {
  • "name": "resource3",
  • "property": "c"
  • }]

响应:

  • HTTP/1.1 201 Created
  • Location: /resources/1,2,3
  • [{
  • "id": "1",
  • "name": "resource1",
  • "property": "a"
  • }, {
  • "id": "2",
  • "name": "resource2",
  • "property": "b"
  • }, {
  • "id": "3",
  • "name": "resource3",
  • "property": "c"
  • }]

删除多个相同的资源

  • // 请求
  • DELETE /resources/1,2,3 HTTP/1.1
  • // 响应
  • HTTP/1.1 204 No Content

修改多个相同的资源

请求:

  • PATCH /resources/1,2,3 HTTP/1.1
  • Content-Type: application/json
  • {
  • "property": "d"
  • }
  • // 也可以使用 JSON Patch
  • Content-Type: application/json-patch+json
  • {
  • "op": "replace",
  • "replace": "/property",
  • "value": "d"
  • }

请求实体可以直接写一个 JSON 进行修改,也可以发送一个 JSON Patch 进行修改。

响应:

  • HTTP/1.1 204 No Content

超文本驱动

想法受启发于 JSON API 方案,做法基本照搬,主要是把 links 相关内容放到了响应头里。

可以添加 schema 参数链接到目标数据的结构描述文档,比如 JSON Schema 、 Schema.org(link:http://schema.org/) 等。

想法目前还不成熟,不建议投入使用。

  • HTTP/1.1 200 OK
  • Link: <http://api.example.com/peoples/{posts.author}>; rel="url-template:author"; allow="COLLECTION,GET"; schema="...",
  • <http://api.example.com/comments/{posts.comments}>; rel="url-template:comments"; allow="COLLECTION,CREATE,GET,DELETE"; schema="...",
  • <http://api.example.com/todos/order>; rel="url-template:order"; allow="GET,PUT"; schema="..."
  • [{
  • "id": "1",
  • "title": "Rails is Omakase",
  • "author": "9",
  • "comments": [ "5", "12", "17", "20" ]
  • }]

错误处理

在调用接口的过程中,可能出现下列几种错误情况:

  • 服务器维护中,503 状态码
    • HTTP/1.1 503 Service Unavailable
    • Retry-After: 3600
    • Content-Length: 41
    • {"message": "Service In the maintenance"}
  • 发送了无法转化的请求体,400 状态码
    • HTTP/1.1 400 Bad Request
    • Content-Length: 35
    • {"message": "Problems parsing JSON"}
  • 服务到期(比如付费的增值服务等), 403 状态码
    • HTTP/1.1 403 Forbidden
    • Content-Length: 29
    • {"message": "Service expired"}
  • 因为某些原因不允许访问(比如被 ban ),403 状态码
    • HTTP/1.1 403 Forbidden
    • Content-Length: 29
    • {"message": "Account blocked"}
  • 权限不够,403 状态码
    • HTTP/1.1 403 Forbidden
    • Content-Length: 31
    • {"message": "Permission denied"}
  • 需要修改的资源不存在, 404 状态码
    • HTTP/1.1 404 Not Found
    • Content-Length: 32
    • {"message": "Resource not found"}
  • 缺少了必要的头信息,428 状态码
    • HTTP/1.1 428 Precondition Required
    • Content-Length: 35
    • {"message": "Header User-Agent is required"}
  • 发送了非法的资源,422 状态码
    • HTTP/1.1 422 Unprocessable Entity
    • Content-Length: 149
    • {
    • "message": "Validation Failed",
    • "errors": [
    • {
    • "resource": "Issue",
    • "field": "title",
    • "code": "required"
    • }
    • ]
    • }

所有的 error 哈希表都有 resourcefieldcode 字段,以便于定位错误,code 字段则用于表示错误类型:

  • invalid: 某个字段的值非法,接口文档中会提供相应的信息
  • required: 缺失某个必须的字段
  • not_exist: 说明某个字段的值代表的资源不存在
  • already_exist: 发送的资源中的某个字段的值和服务器中已有的某个资源冲突,常见于某些值全局唯一的字段,比如 @ 用的用户名(这个错误我有纠结,因为其实有 409 状态码可以表示,但是在修改某个资源时,很一般显然请求中不止是一种错误,如果是 409 的话,多种错误的场景就不合适了)

其他参考:

分页

请求某个资源集合时,可以通过指定 count 参数来指定每页的资源数量,通过 page 参数指定页码,或根据需求使用 last_cursor 参数指定上一页最后一个资源的标识符替代 page 参数。

如果没有传递 count 参数或者 count 参数的值为空,则使用默认值,建议在设计时设置一个最大值。

分页的相关信息可以包含在 Link Header 和 X-Pagination-Info 中( HTTP 头的语法格式可以参考 ABNF List Extension: #rule )。

如果是第一页或者是最后一页时,不返回 previous 和 next 的 Link 。

  • HTTP/1.1 200 OK
  • X-Pagination-Info: count="542"
  • Link: <http://api.example.com/#{RESOURCE_URI}?last_cursor=&count=100>; rel="first",
  • <http://api.example.com/#{RESOURCE_URI}?last_cursor=200&count=100>; rel="last",
  • <http://api.example.com/#{RESOURCE_URI}?last_cursor=90&count=100>; rel="previous",
  • <http://api.example.com/#{RESOURCE_URI}?last_cursor=120&count=100>; rel="next",
  • <http://api.example.com/#{RESOURCE_URI}?last_cursor={last_cursor}&count={count}>; rel="url-template:pagination"
  • [
  • ...
  • ]

相关资料:

其他参考:

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐