V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kuoruan
V2EX  ›  程序员

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

  •  
  •   kuoruan · 2019-03-21 17:11:02 +08:00 · 5133 次点击
    这是一个创建于 2073 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 后端,请问各位这种设计是否符合规范?

    是否有更好设计?

    7 条回复    2019-03-21 22:28:13 +08:00
    icelzh
        1
    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
        2
    index90  
       2019-03-21 18:24:48 +08:00   ❤️ 2
    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
        3
    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
        4
    kuoruan  
    OP
       2019-03-21 19:22:58 +08:00
    @icelzh
    @index90
    ```接口定义应该站在使用方角度去设计``` 获取验证码从用户角度应该使用 GET,但是 GET 是一个幂等的操作,验证码的获取需要每一次访问返回不同的内容,而且浏览器会缓存 GET 请求(可以通过添加 query 的方式规避,但链接中就多了一些无意义的数据),POST 则不存在这个问题。因此我认为 GET URL 中应该添加随机 ID。

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

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

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

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

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

    RESTFul 里面, Get 不要有副作用. 创建验证码就是副作用了. POST, PUT 都好啊.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2726 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 05:37 · PVG 13:37 · LAX 21:37 · JFK 00:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.