RESTful 风格的验证码接口应该如何设计?

2019-03-21 17:11:02 +08:00
 kuoruan

URL: /api/v1/captcha

操作分为获取验证码和验证验证码

当前设计:

获取验证码使用 POST URL,表示创建一个新的验证码,Content body 为

{
	"id": "request id"
}

Body 如果为空的时候,去 Header 里边取 X-Request-ID,如果都为空,则随机生成一条 UUID 作为对应的验证码 ID

返回内容为:

{
	"id": "captcha id",
    "data": "captcha image base64"
}

验证验证码的时候使用 DELETE URL,因为每个验证码只验证一次,相当于删除操作。

Content Body 内容为:

{
	"id": "captcha id",
    "value": "captcha value"
}

验证失败时返回 400 外加失败内容:

{
	"code": 400,
    "message": "captcha verify failed"
}

验证成功时返回 204 空 Body

我第一次写 RESTful API 后端,请问各位这种设计是否符合规范?

是否有更好设计?

4968 次点击
所在节点    程序员
7 条回复
icelzh
2019-03-21 17:51:53 +08:00
获取验证码 GET /api/v1/captcha

请求成功
生成
由 captcha_code = 123 创建记录 captcha_id = 123
返回
captcha_id = 123 保证数据库唯一性
captcha_image = 根据 captcha_code 生成的图片地址

验证验证码 POST /api/v1/captcha
captcha_code + captcha_id 进行验证

验证状态 就是
status ok or no_ok
status_code 错误码
data 就返回的数据
success 成功的文案 不成功就为空
errors 失败的文案 成功就为空
index90
2019-03-21 18:24:48 +08:00
RestFul 不是规范,是一种建议,所以没有唯一答案,但有一个共同的目标,就是尽量在不阅读文字解析的情况下,只需要看 method 和 url,就知道你这个接口在做什么。

1. 获取验证码,感觉你的方案有点技术化思维,虽然对于你后台实现来说,是生成一个验证码,但是对于调用方来说,就是获取一个验证码。接口定义应该站在使用方角度去设计,所以应该用 GET /api/v1/{request_id}/captcha。如果你们的接口规范有要求每一个请求都会有 X-Request-ID,可以简化为:GET /api/v1/captcha。

2. 验证的时候,我习惯用 POST:POST /api/v1/{request_id}/captcha/{id} 或 POST /api/v1/captcha/{id},body 传 value。

这里有个关键问题,RestFul 是为资源的操作而设计的,如果对于“ rpc ”类调用,很难表达“动作”,我是参考 elasticsearch 的 API 设计,他们采用在 URL 末端增加操作字段,例如:POST /api/v1/{request_id}/captcha/{id}/_validate
mcfog
2019-03-21 19:06:16 +08:00
书院派 A
POST captcha/ {type: image}

200 {type: image, requestId, image, status: CAPTCHA_STATUS_INIT}

PATCH captcha/:requestId
{answer: 1234, status: CAPTCHA_STATUS_VERIFIED}

200 {type: image, requestId, image, status, answer, verifyResult: {passed: true/false, error: ...}}

note: 用更多字段表示状态以及后续追加的信息,用 PATCH 修改资源(状态) 表示验证语义

书院派 B
POST captcha/ {type: image}

200 {type: image, requestId, image}

PUT captcha/:requestId/answer
{code:1234}

201

GET captcha/:requestId OR captcha/:requestId/verify-result
{type: image, requestId, image, answer:{code:1234}, verifyResult:{passed: true/false}}

note: 用 sub resource 代表资源的不同部分,创建 sub resource 表示验证语义

老油条派:( restful 反模式)
POST captcha/ {type: image}
POST captcha/:requestId/verify

POST 动词是典型的 restful 反模式, 胜在表达能力好,简单易懂,真香

----------

PS. 个人认为拉取 captcha 不应当用 GET,因为有副作用,不能缓存,也不应该在用户没有干涉的前提下重试
kuoruan
2019-03-21 19:22:58 +08:00
@icelzh
@index90
```接口定义应该站在使用方角度去设计``` 获取验证码从用户角度应该使用 GET,但是 GET 是一个幂等的操作,验证码的获取需要每一次访问返回不同的内容,而且浏览器会缓存 GET 请求(可以通过添加 query 的方式规避,但链接中就多了一些无意义的数据),POST 则不存在这个问题。因此我认为 GET URL 中应该添加随机 ID。

如果直接用用户自己提供 ID 去生成验证码,可能会出现多个用户使用同一 ID 的情况,这种情况理应返回相同的内容,但是不符合验证码的接口需要,所以这个 ID 还得处理一下。

对于 @index90 提到的在链接后边添加操作字段,确实也是一种比较好的方法,但为了保证接口的一致性,是否需要在资源操作的接口后面也加上操作字段?
kuoruan
2019-03-21 19:42:24 +08:00
@mcfog 感谢!

A 方案用 PATCH 改变验证码状态的方式来做验证确实是个新奇的想法,也比较契合 POST 的添加操作。

B 方案是多一次请求吗?而且 PUT 请求有存在则替换,不存在则创建的意思,意思就是创建一个 answer 吗?

C 方案和 @index90 的类似,但是还是我觉得 A 比较厉害
mcfog
2019-03-21 20:01:27 +08:00
@kuoruan put 第二次可以扔个 403 之类的,主要是创建已知 url 的(单个)资源应该用 put,post 一般是向一个集合里提交一个资源(客户端无法控制 url )让服务器返回 url
joesonw
2019-03-21 22:28:13 +08:00
验证码不是跟着请求走的吗? 单独一个验证码验证的话. 验证完标记 session?

RESTFul 里面, Get 不要有副作用. 创建验证码就是副作用了. POST, PUT 都好啊.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/547084

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX