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

接口响应结果应该以请求头里的 Accept 字段为准吗

  •  1
     
  •   dumbbell5kg · 2023-11-14 21:41:41 +08:00 · 1447 次点击
    这是一个创建于 367 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我觉得 Accept 字段就是干这个的,所以应该以 Accept 为准,比如浏览器给的 Accept 为 textPlain,application/json.

    对于这个 Accept 来说,我们的 SpringBoot 应用默认是反了 textPlain 格式,导致请求方报错(对方要 json 格式)。

    我认为这个问题应该让请求方把 Accept 里的 textPlain 去掉来解决。

    但是领导认为接口反什么格式应该是跟请求方通过其他方式(口头)约定好的,不应该要求请求方传指定的 Accpet ,说他搞了好多年没有要求请求方必须传什么 Accept 的,这就导致我要去改 Spring 的 messageConverts 一系列的东西来固定接口的响应格式。

    所以来问下大家,标准的做法是什么?

    20 条回复    2023-11-15 18:05:49 +08:00
    yinmin
        1
    yinmin  
       2023-11-14 21:47:58 +08:00 via iPhone
    你领导说的没错
    GTim
        2
    GTim  
       2023-11-14 21:48:11 +08:00   ❤️ 1
    建议听你领导的,省事。你知道可以这么做即可
    hallDrawnel
        3
    hallDrawnel  
       2023-11-14 22:07:51 +08:00
    本身 accept 就是告诉服务端客户端期望返回什么格式的,你的理解没有问题。但实践上来说,只响应一种稳定的格式会剩下很多麻烦,返回多种格式的情况也不是那么常见。然后又是你 leader 说的,建议听 leader 的。
    pigspy
        4
    pigspy  
       2023-11-14 22:08:11 +08:00
    从 HTTP 协议的标准来看你的说法不错
    但是如果你们的接口仅限于内部调用的话,不在乎 Accept 的格式约束也没啥问题
    dumbbell5kg
        5
    dumbbell5kg  
    OP
       2023-11-14 22:09:53 +08:00
    了解
    monstervivi
        6
    monstervivi  
       2023-11-14 22:30:04 +08:00
    HTTP 响应 Body ,当然是以 Request Header 中的 Accept 字段来准 ,这就是 HTTP 规范呀。

    而且 Spring Web 处理响应 Body 就是按照 Accept 字段来分不同逻辑来处理。

    参考 [AbstractMessageConverterMethodProcessor#writeWithMessageConverters]( https://github.com/spring-projects/spring-framework/blob/main/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java#L224C1-L224C1)

    连 Spring 都是按此来作为标准,所以我认为这就是标准做法。
    tool2d
        7
    tool2d  
       2023-11-14 22:45:21 +08:00 via Android
    昨天对接讯飞大模型,让他不要 accpet ,但是挡不住写服务器的野路子,只有一种 text/event 返回格式。
    monstervivi
        8
    monstervivi  
       2023-11-14 22:55:03 +08:00
    不过如果要修改,应该也不用修改 Spring 的 MessageConverter 吧?

    @RequestMapping 注解,可以加上 consumes 值呀,例如: @GetMapping(value = "x" consumes = "*/*")
    xmumiffy
        9
    xmumiffy  
       2023-11-14 22:58:34 +08:00 via Android
    按照标准来,又想只返回 JSON ,那可以检测到非期望的 Accept 就返回 406
    monstervivi
        10
    monstervivi  
       2023-11-14 23:05:06 +08:00
    @monstervivi

    修正: 应该是加上 produces ,例如 @GetMapping(value = "x", produces = "application/json;charset=UTF-8")
    leonshaw
        11
    leonshaw  
       2023-11-15 00:49:19 +08:00
    听领导的。如果接口支持 text/plain ,那根据客户端传入的 Accept 选择 text/plain ,没问题。但领导的意思的是,服务端根本就不应该支持 text/plain ,接口应当约定一种固定格式,这个时候就应该忽略 Accept 头。

    RFC 9110 12.1. Proactive Negotiation
    A user agent cannot rely on proactive negotiation preferences being consistently honored, since the origin server might not implement proactive negotiation for the requested resource or might decide that sending a response that doesn't conform to the user agent's preferences is better than sending a 406 (Not Acceptable) response.
    IvanLi127
        12
    IvanLi127  
       2023-11-15 01:03:36 +08:00 via Android
    首先我认为你的领导在狡辩,你明明是要求请求方不要传错误的 Accept 的值,他却说你是要求对方传 application/json 。乱调接口不解决,解决正常实现只有在特殊情况下适用。

    不过你的领导结论是对的,程序不要输出预期以外的东西,他表面再想要 text 也不给他返。


    反正他是领导,他说啥就是啥,要是我,说清楚这样做的后果是啥,然后听领导的决定执行。。。要是可以的话,我会给传那个 Accept 的请求返 400 的空响应。
    chairuosen
        13
    chairuosen  
       2023-11-15 01:33:29 +08:00
    协议标准跟工程实践的区别
    xuanbg
        14
    xuanbg  
       2023-11-15 01:33:29 +08:00
    标准的做法就是提供一种固定的数据格式,Accept 什么的,暂不支持。哈哈哈
    dumbbell5kg
        15
    dumbbell5kg  
    OP
       2023-11-15 08:47:31 +08:00
    @monstervivi 接口太多了,得调整 spring 的默认行为
    dumbbell5kg
        16
    dumbbell5kg  
    OP
       2023-11-15 08:53:02 +08:00
    @leonshaw 这里的 user agent 是浏览器吧,那这段话的意思是浏览器不能指望服务器遵守 accept 字段的规则?
    lzrainchen
        17
    lzrainchen  
       2023-11-15 10:28:49 +08:00
    你说的这个标准术语叫 内容协商( ContentNegotiation ),Spring MVC 其实已经帮你做好了,可以查询一下相关信息
    julyclyde
        18
    julyclyde  
       2023-11-15 11:39:39 +08:00
    虽然你是对的,但不要“你觉得”
    标准写啥样就是啥样
    flyingghost
        19
    flyingghost  
       2023-11-15 14:59:30 +08:00
    按规范做,是一种良好编程实践。
    你可以指望你和你们的合作公司互相约好了“当你表面上说'不要'的时候,实际上你说的是'要'”。这时候不按规范是可接受的,沟通成本和开发成本都可控。
    但你不能指望 github 开放它的 API 的时候和所有的潜在调用者做这样的沟通。于是使用现有共同认可的标准是最经济的做法。

    但各种头本身就是一种“协商”机制。包括 content-type 协商,包括缓存协商。
    它可以实现为“我期望最好是 xxxxx”,而不是“我要求一定是 xxxxx”。

    例如,客户端可以写他请求 text/plain, application/json ,服务端可以实现为我尊重你的选择,尽可能匹配你的需求,如果找不到,fallback 到默认值 json 并返回。
    这也为未来“可能”的扩展开放。
    例如,昨天客户端说我需要 text/plain, application/xml ,服务端说对不起我只有 json 。
    今天服务端进化了,提供了 json 和 xml 两种序列化方法,同样的请求今天就可以按用户需求提供 xml 响应。

    至于这样的“扩展”会不会发生,也许这辈子都不会有。但至少它今天既满足了标准拥抱了变化,又满足了你 leader 的要求。
    julyclyde
        20
    julyclyde  
       2023-11-15 18:05:49 +08:00
    @flyingghost 这需要阉割服务器的 text 能力,才能实现“对不起我只有 json”

    客户端声明 text 和 json 都行,但实际上只能 json ,那是客户端声明的有问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2713 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 12:23 · PVG 20:23 · LAX 04:23 · JFK 07:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.