接口响应结果应该以请求头里的 Accept 字段为准吗 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
dumbbell5kg
V2EX    程序员

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

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

    我觉得 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
    你领导说的没错
    yemoluo
        2
    yemoluo  
       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= "*/*")
    106npo
        9
    106npo  
       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=")
    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     Solana     2700 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 06:13 PVG 14:13 LAX 22:13 JFK 01:13
    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