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

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

  •  1
     
  •   dumbbell5kg · 361 天前 · 1446 次点击
    这是一个创建于 361 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我觉得 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  
       361 天前 via iPhone
    你领导说的没错
    GTim
        2
    GTim  
       361 天前   ❤️ 1
    建议听你领导的,省事。你知道可以这么做即可
    hallDrawnel
        3
    hallDrawnel  
       361 天前
    本身 accept 就是告诉服务端客户端期望返回什么格式的,你的理解没有问题。但实践上来说,只响应一种稳定的格式会剩下很多麻烦,返回多种格式的情况也不是那么常见。然后又是你 leader 说的,建议听 leader 的。
    pigspy
        4
    pigspy  
       361 天前
    从 HTTP 协议的标准来看你的说法不错
    但是如果你们的接口仅限于内部调用的话,不在乎 Accept 的格式约束也没啥问题
    dumbbell5kg
        5
    dumbbell5kg  
    OP
       361 天前
    了解
    monstervivi
        6
    monstervivi  
       361 天前
    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  
       361 天前 via Android
    昨天对接讯飞大模型,让他不要 accpet ,但是挡不住写服务器的野路子,只有一种 text/event 返回格式。
    monstervivi
        8
    monstervivi  
       361 天前
    不过如果要修改,应该也不用修改 Spring 的 MessageConverter 吧?

    @RequestMapping 注解,可以加上 consumes 值呀,例如: @GetMapping(value = "x" consumes = "*/*")
    xmumiffy
        9
    xmumiffy  
       361 天前 via Android
    按照标准来,又想只返回 JSON ,那可以检测到非期望的 Accept 就返回 406
    monstervivi
        10
    monstervivi  
       361 天前
    @monstervivi

    修正: 应该是加上 produces ,例如 @GetMapping(value = "x", produces = "application/json;charset=UTF-8")
    leonshaw
        11
    leonshaw  
       361 天前
    听领导的。如果接口支持 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  
       361 天前 via Android
    首先我认为你的领导在狡辩,你明明是要求请求方不要传错误的 Accept 的值,他却说你是要求对方传 application/json 。乱调接口不解决,解决正常实现只有在特殊情况下适用。

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


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

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

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

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

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