对于 restfulAPI,一般如何选择交换数据的格式呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
temberature

对于 restfulAPI,一般如何选择交换数据的格式呢?

  •  
  •   temberature 2015 年 9 月 17 日 via iPad 12250 次点击
    这是一个创建于 3872 天前的主题,其中的信息可能已经有所发展或是发生改变。
    主要想请教类似 a=1&b=2 和{ a : 1 , b : 2 }这两种的区别
    第 1 条附言    2015 年 9 月 17 日
    使用场景: web 单页应用

    返回数据用 json 没疑问,问题在 post 某个数据时有这两种做法。

    我认为应该传 json ,这样收发数据统一,传递时也不用转换,另一种观点认为应该用 a=1&b=2 这种,有两个理由: 1 、比较省流量 2 、发或修改数据一般比较简单,完全可以表达
    64 条回复    2015-09-19 10:49:53 +08:00
    matthewgao
        1
    matthewgao  
       2015 年 9 月 17 日 via Android
    通常用 json
    crs0910
        2
    crs0910  
       2015 年 9 月 17 日
    这是什么意思?不是 GET 和 POST 吗?
    vainly
        3
    vainly  
       2015 年 9 月 17 日
    如果是 GET 请求,请求参数要在请求地址后"http://ip:port/doman?a=1&b=1&c=1"
    如果是 POST 请求,而且交互使用 JSON 数据格式的话,参数传递会是这样的"{a:1,b=2,c=3,...}"
    mithvv
        4
    mithvv  
       2015 年 9 月 17 日
    get
    a=1&b=2&arr[]=3&arr[]=4
    post
    {
    a:1,b:2,c:[3,4]
    }
    morethansean
        5
    morethansean  
       2015 年 9 月 17 日
    POST 传出去不还是 a=1&b=c
    除非你是自定义的 value 值是 json 格式比如 a=1&b=%7Bc%3A%205%7D

    > decodeURIComponent ('%7Bc%3A%205%7D')
    > "{c: 5}"
    jhaohai
        6
    jhaohai  
       2015 年 9 月 17 日
    json ,感觉已经成为标准了
    wshcdr
        7
    wshcdr  
       2015 年 9 月 17 日
    json 已经是事实上的标准了
    learnshare
        8
    learnshare  
       2015 年 9 月 17 日
    JSON 几乎作为标准存在了,虽然数据量会大一些
    temberature
        9
    temberature  
    OP
       2015 年 9 月 17 日
    相关的帖子
    Json VS Protobuf t/186561
    IOS 开发怎么处理数据类型问题? t/140470
    为什么……不拿另一个 HTTP 服务器来当作数据库来给一个 Web App 使用? t/120678
    morethansean
        10
    morethansean  
       2015 年 9 月 17 日
    不管你提交是否是 JSON ,转换总是需要的,特别是提交数据肯定是需要经过服务器端校验和安全处理的。
    而且大多时候提交的数据又不是直接丢数据库去储存的,增删查找需要的字段,和返回的结果本来有些时候就相差甚远,处理逻辑也完全不一样,没必要强行 JSON 格式。
    temberature
        11
    temberature  
    OP
       2015 年 9 月 17 日
    @morethansean 我说的转换是指这两种字符串能表达的数据结构是等价的,如果只有一种,只需要在一种交换数据和程序变量之间转换。我没有说一定要用什么,只是想知道请教下是否有区别,以及各自的利弊又是什么?
    temberature
        12
    temberature  
    OP
       2015 年 9 月 17 日
    @learnshare 感觉都浪费在双引号上了
    matthewgao
        13
    matthewgao  
       2015 年 9 月 17 日
    @vainly ”如果是 GET 请求,请求参数要在请求地址后"http://ip:port/doman?a=1&b=1&c=1" “ 这个似乎不是很符合 RESTful 的建议吧
    lyz1990
        14
    lyz1990  
       2015 年 9 月 17 日
    json ,事实标准
    temberature
        15
    temberature  
    OP
       2015 年 9 月 17 日
    用 JSON 构建 API 的标准指南
    http://jsonapi.org/
    http://jsonapi.org.cn/
    hantsy
        16
    hantsy  
       2015 年 9 月 17 日   6
    @temberature 首先搞清楚什么是 REST 。

    InfoQ 上有 Fielding 博士的原始论文的中文翻译版本。

    广泛的讲 REST 不限于 HTTP 协议,数据交换格式可以是文本也可以是二进制。狭义的讲,我们通常将 REST 限于 HTTP , JSON 是取常用的数据交换格式, XML 也没问题。

    REST 的几个要素:
    1. 用一个唯一的 URI 代表资源的定位
    2. 用 HTTP 语义( GET , POST , PUT , PATCH , DELETE , HEAD , OPTION 等)操作资源
    3. 用 HTTP 状态标志操作结果

    常用的 CRUD REST API 可以这样设计:

    比如常见的 BLOG 程序,定义一个 /posts 入口。

    /posts , GET , 取得所有 POST ,结果是一个 [{},{}]数组,可以接查询参数?page=XXX 等,返回 200 状态。
    /posts , POST , 发布新 POST , Request Body 为{title:"text", body:"test body"}, 返回 201 状态。

    /posts /{id}, GET , 取得所有单个 POST , URI 需要接 id, 成功返回 200 状态,失败 404 。
    /posts /{id} , PUT , 更新 POST , Request Body 为{title:"text", body:"test body"}, 返回 204 状态。
    /posts /{id} , DELETE , 删除 POST , 成功 返回 204 状态。

    /posts 是对资源集合操作,/posts/{id}对单个资源操作。操作的结果有的有返回数据,更直接的表达结果是 HTTP Status 。

    我写的简单的例子, https://github.com/hantsy/angularjs-springmvc-sample
    这个例子,目前没写任何 Notes 来描述。

    要了解 REST API 实现,可以看另外一个类似的例子 https://github.com/hantsy/angularjs-grails-sample , 这个项目的 WIKI 上的详细介绍。

    @temberature 从 REST API 设计角度,你的问题和 REST 一点关系都没有。从设计上角度,查询数据?a=1 仅适用条件过滤,也就是上面第一个 /posts GET 方式。

    另外,关于 REST API 设计好坏,有一个 Rechardson 成熟度模型来衡量。它定义了三个级别。国内几个一线大公司的 API 基本都是 Level 0 , 按这个标准衡量来讲,都不是 REST API ,虽然他们 Developer 网站都喜欢写上 REST 的字样。反而一些不大的公司做得不错,比如 JPUSH 等。

    当我们考虑 Level3 ( Self-document, Self-Discovery ) 的时候,在交换格式上就有很多细节要去实现。这方面有一些行业标准或者正在标准化的交换格式。

    如: HAL , Collection+JSON , JSON API 。
    hantsy
        17
    hantsy  
       2015 年 9 月 17 日
    @matthewgao GET 是用于查询操作,是可以使用 query parameters 的。
    hantsy
        18
    hantsy  
       2015 年 9 月 17 日   1
    @temberature JSON API 目前应用范围不广,不如 HAL 流行, Spring 目前只支持 HAL 。
    refear99
        19
    refear99  
       2015 年 9 月 17 日
    取就用 get+query
    增删改就用 POST DELETE PUT + json body
    temberature
        20
    temberature  
    OP
       2015 年 9 月 17 日
    @hantsy 博士的论文我翻过几次,我知道数据交换并不是 rest 的主要关注点,只要想请教下在实际的做法以及如何取舍,感谢分享~
    hantsy
        21
    hantsy  
       2015 年 9 月 17 日
    @temberature 我上面两个链接的例子中 UI 全部是 SPA 。
    gamexg
        22
    gamexg  
       2015 年 9 月 17 日
    直接 command_json , sign 。

    a=1&b=2 这种做 hash 签名容易被坑死。
    temberature
        23
    temberature  
    OP
       2015 年 9 月 17 日
    @gamexg 没太明白,能再具体解释下吗:)
    loading
        24
    loading  
       2015 年 9 月 17 日 via Android
    如果省流量你考虑进去,这问题就没必要讨论了。
    hash 你后面掉坑就知道了。
    temberature
        25
    temberature  
    OP
       2015 年 9 月 17 日
    @loading 清楚利弊,在具体情况下就好取舍了吧;能描述下这个坑的大小、颜色、气味吗?以免掉下水道里,哈哈~
    gamexg
        26
    gamexg  
       2015 年 9 月 17 日
    比如一些 http 请求为了安全需要做 hash 签名, a=1&b=2 这种签名会碰到很多坑。

    看一下这个 hash 签名设计:
    https://blog.yanke.io/she-ji-yi-tao-ji-yu-hash-qian-ming-yan-zheng-de-api/

    ```
    因此我初步设计了一个签名机制,步骤如下:

    将时间戳,随机串, TokenID ,和业务逻辑关键参数构成一个字典
    将字典按照 Key 升序排序,然后按照 key1 value1 key2 value2 拼成一个连续字符串
    将 Path 拼在前面, Token 拼在后面
    将整个字符串做 SHA256 ,作为一个参数放回到请求中
    服务器端接收到请求的时候也进行同样的处理,进行签名验证。

    如果你曾经裸写过常见的第三方服务 API 调用的话,你会对这些步骤非常熟悉。
    ```

    如果直接传递 json 字符串,直接 hash json 字符串即可,不用麻烦的拼接了。
    temberature
        27
    temberature  
    OP
       2015 年 9 月 17 日
    @gamexg 只理解到处理方式的差别,没看到坑
    wangleineo
        28
    wangleineo  
       2015 年 9 月 17 日   1
    还是统一用 JSON 好些吧,用 Form 提交的话,多层数据怎么办?
    FrankFang128
        29
    FrankFang128  
       2015 年 9 月 17 日
    都支持就好了
    temberature
        30
    temberature  
    OP
       2015 年 9 月 17 日
    @FrankFang128 这样只是把问题抛给了调用接口方吧
    hantsy
        31
    hantsy  
       2015 年 9 月 17 日
    @gamexg 难道不用 HTTPS 吗?签名这东西,看着就吐,根本谈不上安全,如果你的 Token 被截取(没 HTTPS 所有数据传输都透明), Hacker 构造你这样顺序的签名有什么难的。这也是 oAuth2 去掉了签名,强制使用 HTTPS 的原因。
    marginleft
        32
    marginleft  
       2015 年 9 月 17 日
    pandada8
        33
    pandada8  
       2015 年 9 月 17 日
    不是取决于 Accept 头的么……
    pandada8
        34
    pandada8  
       2015 年 9 月 17 日
    @pandada8 哦没看清附言……
    主要看你的 spa 框架……比如 angular 默认 post 是 json ……
    总之怎么方便怎么来
    iyaozhen
        35
    iyaozhen  
       2015 年 9 月 17 日
    这个取决于你的操作吧。 GET 获取数据,可以用 urlencode 传参。 POST 用于更改数据,传 json 更合适吧。
    temberature
        36
    temberature  
    OP
       2015 年 9 月 17 日
    @pandada8 如果接口是不同的人在写,那还要看是谁方便,有一套参考的规范会更好吧
    aftereclipse
        37
    aftereclipse  
       2015 年 9 月 17 日
    统一 HTTP POST , json 数据格式,客户端和服务端都好写,加解密也好做
    vainly
        38
    vainly  
       2015 年 9 月 17 日
    @matthewgao 不是啊,对于指定参数的 GET 请求时这么做的。
    比如这样:
    @GET
    @Path ("findById")
    public String findById (@QueryParam ("id")String id );
    temberature
        39
    temberature  
    OP
       2015 年 9 月 17 日
    @vainly 没看懂,()
    pandada8
        40
    pandada8  
       2015 年 9 月 17 日
    @temberature 最后当然要统一了……之前先做好协定。
    比如有 angular,superagent 之类的场合我倾向于使用 json
    有些时候框架搭配用 jquery 发请求那就用 form-urlencoded.
    总体而言就是怎么方便怎么来

    实在决定不了么
    来局昆特牌吧
    gamexg
        41
    gamexg  
       2015 年 9 月 17 日
    @temberature 你需要保证前后端的排序、编码等是一致的。记得有一篇 API 文档提到过,个别语言的排序和 API 服务器不一致,需要特殊处理。


    @hantsy 即使上了 https ,我也会利用类似签名的方式而不会直接传递 API 密钥做身份认证的。例如目前对于设备的认证就是设备注册时分配一个 id 及密钥,每个请求都会被 hash 签名。密钥只会在设备注册时传递一次,之后不会传递,这个风险还是可以接受的。由于密钥不像密码,更换麻烦,后期即使加上 https ,也不会直接传递密钥。
    railgun
        42
    railgun  
       2015 年 9 月 17 日
    json 适合用来描述复杂的数据格式
    如果只是简单的数据,用哪个都无所谓
    还是要从实际出发,比如有的接口是要传文件的,用 json 就不合适了
    FrankFang128
        43
    FrankFang128  
       2015 年 9 月 17 日
    @temberature 支持两种方式的话,就没有问题了呀。 调用方怎么都不会错,怎么叫推给他们。
    FrankFang128
        44
    FrankFang128  
       2015 年 9 月 17 日
    楼上说什么 JSON 是事实标准的说法有点问题,
    application/x-www-form-urlencoded; 也是标准啊。

    按 REST 来说,根据 Content-Type 的值为 application/x-www-form-urlencoded 还是 application/json 做下判断就好了。
    temberature
        45
    temberature  
    OP
       2015 年 9 月 17 日
    @FrankFang128 我的意思不是把麻烦推给他们,是把分析两种方式的利弊推给了他们;在接口方,我倾向在理想情况把一种实现好,毕竟现实中资源和精力是有限的;同意都是标准的说法,但是事实标准是可能存在的。
    jokcy
        46
    jokc  
       2015 年 9 月 17 日
    @morethansean 你可以用 payload 的方式传数据
    temberature
        47
    temberature  
    OP
       2015 年 9 月 17 日
    @pandada8 有时候确实会遇到自己难以决定或者双方难以一致的问题,这时候我的态度就先实现一种(直觉有时候也管用),在使用经验增长之后,答案自然就有了。 ps :突然想到“约定大于配置”。
    temberature
        48
    temberature  
    OP
       2015 年 9 月 17 日
    @railgun 文件确实特殊;一个项目中应该都有复杂点的数据,统一的约定还是挺重要的吧
    temberature
        49
    temberature  
    OP
       2015 年 9 月 17 日
    @gamexg hash 时 json 字符串中的顺序也需要注意吧
    temberature
        50
    temberature  
    OP
       2015 年 9 月 17 日
    @jokcy 一直没太明白设计这个的目的
    gamexg
        51
    gamexg  
       2015 年 9 月 17 日
    @temberature 客户端是对序列化后的字符串签名,服务端是先验证签名后反序列化,所以不涉及 key 顺序的问题。
    temberature
        52
    temberature  
    OP
       2015 年 9 月 17 日
    @gamexg 也见过接口的字符串签名算法,其实也可以按 json 这种,不明白为什么要排序:)
    FrankFang128
        53
    FrankFang128  
       2015 年 9 月 17 日
    我觉得没必要 2 选 1 的,两种同时存在是 OK 的,也是更为常见的。
    yield9tk
        54
    yield9tk  
       2015 年 9 月 17 日
    两种可以同属存在。不同的压缩方式,在 accept 中设置即可
    railgun
        55
    railgun  
       2015 年 9 月 17 日
    @temberature 那就 json 吧,适配性好一点,扩展也方便
    hantsy
        56
    hantsy  
       2015 年 9 月 17 日
    @gamexg 一些 oAuth2 provider 提供了 JWT 支持, 连接的时候使用, Spring 内置了支持(只需要设置)。其他情况真的没看到签名的使用。国内 X 宝 X 度通篇的 Sign ,除了让 API 看起来像屎一样,如果它的加密方法和顺序被预先知道了,我不觉得是安全的。

    如果你想做所有请求还要加密, X509 应该可以了吧。我想只有银行级的安全才会有这种要求。
    Geoion
        57
    Geoion  
       2015 年 9 月 17 日
    两个尖括号的流量也省。。。。。
    temberature
        58
    temberature  
    OP
       2015 年 9 月 17 日
    @Geoion 对于用户量亿级的服务,还是有大差别的吧
    jokcy
        59
    jokcy  
       2015 年 9 月 17 日
    @temberature content-type 不一样
    hantsy
        60
    hantsy  
       2015 年 9 月 17 日
    @temberature 针对 Mobile 原生程序(比如 Android , IOS )的某些场合可以绕开 HTTP ,特别图片等数据量大的东西,使用更底层的协议通讯,效率更高。其它文本类的,全部用 JSON ,所有平台都通用。

    其实, REST API 的设计,只要参考 Github API , 或者 Heroku 的 API 就好了。设计好的 API ,从根到底下资源是一个树型结构,如 / 是根, /posts 是 Post 资源集合, /posts/2 是 ID 为 2 的单个资源,/posts/2/comments ,是指 ID 为 2 的 Post 下面的所有 Comments 。如果使用 HAL , 从根开始添加一些必要的 metadata 信息, 下面的所有的资源都应该是可以 Discovery 的,使用 HAL Browser 这样工具是可以可视化整个 API 结构,而不需要借助文档说明。
    morethansean
        61
    morethansean  
       2015 年 9 月 18 日
    @jokcy web 单页应用直接 form data 不好么。
    jokcy
        62
    jokcy  
       2015 年 9 月 18 日
    @morethansean 不是不好,而是根据你们自己的需求自己定义,你这边以 form 格式传后台就以 form 格式接收并转换,用 json 的好处就是如果你的后台用的是类似 node 这样天生支持 json 数据的,那么就无需转换了。
    matthewgao
        63
    matthewgao  
       2015 年 9 月 19 日
    @hantsy 我再补充一下, REST 还要注意状态转移和等幂性
    matthewgao
        64
    matthewgao  
       2015 年 9 月 19 日
    @hantsy 多谢,我之前还没看到任何标准和参考说道到这个是可以的,反倒刻意去回避这个
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3036 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 112ms UTC 10:54 PVG 18:54 LAX 03:54 JFK 06:54
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86