HTTP接口设计

状态码

请求成功

200 OK : 请求执行成功并返回相应数据,如 GET 成功
201 Created : 对象创建成功并返回相应资源数据,如 POST 成功;创建完成后响应头中应该携带头标 Location ,指向新建资源的地址
204 No Content : 请求执行成功,不返回相应资源数据,如 PATCH , DELETE 成功

重定向

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

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

客户端出错

400 Bad Request : 请求体包含语法错误
401 Unauthorized : 需要验证用户身份,如果服务器就算是身份验证后也不允许客户访问资源,应该响应 403 Forbidden
403 Forbidden : 服务器拒绝执行
404 Not Found : 找不到目标资源
405 Method Not Allowed : 不允许执行目标方法,响应中应该带有 Allow 头,内容为对该资源有效的 HTTP 方法
406 Not Acceptable : 服务器不支持客户端请求的内容格式(比如客户端请求 JSON 格式的数据,但服务器只能提供 XML 格式的数据)
409 Conflict : 请求操作和资源的当前状态存在冲突
410 Gone : 被请求的资源已被删除
412 Precondition Failed : 服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。主要使用场景在于实现并发控制
413 Request Entity 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 是表示客户端或许可以这么做,但服务端还没有实现这个功能

错误处理

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

服务器维护中,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": "missing_field"
    }
  ]
}

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

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

数据缓存

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

$ curl -i http://api.example.com/#{RESOURCE_URI}
HTTP/1.1 200 OK
Cache-Control: private, max-age=60
ETag: "644b5b0155e6404a9cc4bd9d8b1ae730"
Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT

$ 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: private, max-age=60
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: private, max-age=60
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
客户端发起的请求提供的条件符合实际值,那就更新资源,响应 200 OK 或者 204 No Content ,并且包含更新过的 Last-Modified 和/或 ETag 头,同时包含 Content-Location 头,其值为更新后的资源 URI

User-Agent

请求头中的 User-Agent 可以帮助服务端收集设备信息,建议格式:

iOS

iOS/iOS版本号 (设备型号; 是否越狱; 网络类型; 语言) CFBundleIdentifier/CFBundleVersion

Android

Android/Android版本号 (设备型号; ROM版本号; 是否root; 网络类型; 语言) 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

你可能感兴趣的:(HTTP接口设计)