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

请教后端同学这种写接口的方式对不对?

  •  
  •   firhome · 2022-01-14 11:44:15 +08:00 · 12957 次点击
    这是一个创建于 804 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如:请求一本 book 的订单信息

    [以前] 1.请求后端 bookinfo 接口,bookinfo 返回 data:{}, 包含了 book 的基本信息,book 的订单信息和订单状态(出售中,下架 等)

    2.前端直接渲染数据即可。

    [现在] 1.请求后端 bookinfo 接口 返回 book 基本信息 2.根据 bookinfo 接口获取 book 的 id ,再去请求 bookOrderInfo 获取订单信息 3.根据 book id 和 bookOrderInfo 里面订单 id ,再去请求个接口获取订单状态。

    导致我初始化页面要发 3 个请求。

    想问下 [现在] 这是个什么情况。是后端不愿意给我们包吗?喊他加数据感觉很艰难。很多东西得前端做。如果是这样的话,是不是后面前端可以写 node 来包一层?

    第 1 条附言  ·  2022-01-14 18:03:07 +08:00
    额,没想到有这么多回复了。谢谢大家。

    我再说具体点吧。

    其实就是 查看订单列表页。

    [没毛病] 列表页:getBookOrderList

    详情页:
    0.通过 url 传递 orderid 进来。
    页面要展示 book 的信息,book 的订单信息,以及展示 book 乱七八糟的 status
    1.请求后端 bookinfo (通过 orderid 查 bookid 和 bookinfo)、
    2.请求后端 bookorderInfo (通过 bookid ,orderid 查 信息)
    3.请求后端 bookorderInfostatus (通过 orderid 来获取)
    == 页面 loaded 展示==


    其实这不是最搞的。

    最搞的是 token 登录态,如果快过期了,提供了个刷新 token 的接口给前端,喊前端发现 token 要过期了就去刷一下接口(额外请求)

    其实我请求里登录后都带上 token 了。为啥还要前端来做这个操作?
    154 条回复    2022-01-17 17:12:06 +08:00
    1  2  
    wunonglin
        101
    wunonglin  
       2022-01-14 18:38:59 +08:00 via iPhone
    @hhjswf 这看你业务来着。我自己预想的是订单这个整体是一个服务
    shunia
        102
    shunia  
       2022-01-14 18:51:00 +08:00   ❤️ 1
    @chtcrack #61 光想后端逻辑没审需求吧,你说的技术基础是对的,如果说三个接口的展现分别在三个不同的地方或者都需要可以单独用来获取数据,你说的这种情况是有意义的,承载量的计算也没什么问题。
    但是题主说的这里是一个界面同时需要这三份数据,那么你说的根本就是鬼扯,因为每个用户一进这个页面就是三个请求,刷新也是,那就不存在你说的问题,而且因为 http(s) 链接的特性,实际上还会消耗更多网络和服务器资源。
    这里前端确实可以自行做聚合,难度也不高,虽然接口相互有依赖会延长请求时长降低总体请求的完成率,但是在当下的用户体验里可以做占位型展示,可以通过体验降低用户的失望。
    不过所有从后端的角度说不应该分开的也完全是瞎说,总归是要根据业务需求实际处理,这个页面从题主目前的需求里看,属于可以前端聚合也可以后端聚合的情况,如果可以用到缓存的话其实更应该后端聚合。如果做后端真的只需要按表查询提供接口,那全都用 graphql 得了。
    lujiaosama
        103
    lujiaosama  
       2022-01-14 19:22:15 +08:00
    token 过期了接口报错了然后前端去请求接口重新刷新 token 这是正常操作, 难道你想后端帮你刷新?接口顺便返回一个新 token 给你?这就不科学了.
    adoal
        104
    adoal  
       2022-01-14 19:27:38 +08:00 via iPhone
    graphql 就是为这种需求而来的
    rabbbit
        105
    rabbbit  
       2022-01-14 19:45:06 +08:00
    看了后面补的说明,我认为这个查订单状态这个聚合应该后端做.
    毕竟后台订单管理详情一般都是要直接展示订单状态的,没人会点开订单详情然后再点个按钮查订单状态.
    可以这样,以后提需求在群里 @他,所有交流都留记录.别明面上在有同事的时候跟他急眼,在试用期没过前找领导反应.
    rabbbit
        106
    rabbbit  
       2022-01-14 19:46:46 +08:00
    领导也不管的话,我建议代码和人有一个能那啥就行,你懂的.
    wdytoya
        107
    wdytoya  
       2022-01-14 19:47:19 +08:00   ❤️ 4
    作为后端同学来说一下我的想法,仅供讨论

    其实你说的 12 两种方案都可以,我这都用过,具体用哪种方案取决于你具体的业务场景
    1 方案的核心含义在于一次性返回全量数据,优势自然是减少前端请求次数,也相应减少多次网络上的开销,但劣势也很明显,因为你需要聚合完所有数据才能渲染,如果数据量较多,耗时较长,在用户 C 端上的体验就很糟糕,会有长时间的白屏,即便有些业务用 loading 态或者骨架图来兜底体验也不会好到哪去
    2 方案的核心含义在于按需索取,优势在于你可以先渲染核心数据,非核心的数据增量渲染,特别是在一些动静分离的页面设计上是很有优势的。劣势自然就是增加了前端的请求次数,增加了网络开销和网络抖动可能导致的异常几率

    而像楼主附言所说的两个页面,一个是订单列表页,一个是订单详情页
    针对订单列表页,其实核心展示信息不多,主要是商品图标、商品名、订单 ID 、订单状态,其实是没必要返回商品全量信息的,所以如果按你们现在的方案 2 的设计去调一个批量接口或者分页接口是没毛病的
    针对订单详情页,由于一般都是纯静态数据,而且用户不需要太多的行动点,这时候确实是可以一次性返回订单全量信息的,所以用类似于方案 1 的接口设计就会更合适

    最后再说一下楼主说的刷 token ,这个楼主没理解为什么需要前端刷,其实楼主如果是 PC 时代过来的前端可能就不会很难理解了,一些文档编辑框页面的刷新就是一个经典的例子。因为页面是静态的,用户一直停留在页面上后端是不知道的,只有前端自己知道,而如果前端不去定期刷新状态,那么就会出现一种情况,用户在 token 过期之后在页面上执行了某个提交操作,结果由于 token 过期无法提交,可能在你第二时间才去做刷新操作之后,用户可能页面上填写的东西没保存下来就没了,那用户体验也是很糟糕的,当然有些做法是可以保存页面填写内容的,那为什么不直接就在过期的时候就提醒他要主动刷新了呢?
    当然这里面还是可以说取决于你具体的业务场景,因此如果你们的产品对于第二时间再去做强制刷新觉得没有大问题,那也可以不用前端定期 refresh ,主要还是看第二时间的强制 refresh 会不会存在打断用户主流程的问题来决定
    xiangyuecn
        108
    xiangyuecn  
       2022-01-14 22:12:32 +08:00
    针对 商品、订单 两个东西的基础信息接口:
    请求两个接口,前后端均合理。
    请求三个接口,后端不合理。
    请求一个接口,前后端均完全不合理。
    xiangyuecn
        109
    xiangyuecn  
       2022-01-14 22:18:28 +08:00
    至于 token ,后端应该是用的哪个全家桶,标准操作。只需前端对请求封装好了,不管是提前刷新也好重试刷新也好,完全可以做到上层代码无感知。
    Leviathann
        110
    Leviathann  
       2022-01-14 22:18:49 +08:00
    方式 2 大概能理解为什么
    但是有个问题是这种方式中,如果列表的查询需要用订单或者 status 的字段做查询或者排序怎么搞
    Vitta
        111
    Vitta  
       2022-01-14 22:37:03 +08:00
    你们后端是 java 吧
    leonme
        112
    leonme  
       2022-01-14 23:10:48 +08:00
    其实拆分的挺合理的
    ZSeptember
        113
    ZSeptember  
       2022-01-15 00:04:30 +08:00   ❤️ 1
    RESTful API 就是这样的,很多逻辑在前端。后端只负责业务建模,不负责前端 UI 逻辑,因为业务逻辑不会经常改变,但是 UI 逻辑经常改变。
    所以现在有 BFF 的架构,一般使用 GraphQL 做 BFF 中间层。
    dayeye2006199
        114
    dayeye2006199  
       2022-01-15 02:33:43 +08:00
    token 这个不要犟,token 过期属于常规操作;前端可以做一些封装,请求代码写起来就没区别了
    Samuelcc
        115
    Samuelcc  
       2022-01-15 02:53:33 +08:00 via Android
    作为后端,我觉得订单信息和书籍信息拆开挺合理的。一个是数据量和分页的问题,一个是如果前端不同页面需要不同的数据后端都要写一个对应的聚合接口,会经常需要上线,代码难以维护,耦合严重,后续如果服务要进一步拆分就是兼容地狱。
    分成多个接口也能一定程度避免单个微服务故障导致整个页面不可用的问题,前端可以异步请求显示,如果订单显示得慢也不耽误用户查看书籍信息。
    对于比较复杂的业务,加个动态聚合层可能会更好。
    不过也反思了下自己平时总是仅考虑后端的逻辑上要干净好维护,没怎么考虑前端的体验,可能前端也做得很痛苦。以后会多交流。
    lanbos
        116
    lanbos  
       2022-01-15 06:58:38 +08:00 via Android
    刷 token 是必要的楼上的解释的很明白了。聚合层肯定得有,这种脏代码容易变化的部分肯定得有人做,无非是成本问题,小业务通常前端聚合成本最低,搞个中间层维护成本更高。。。。
    markgor
        117
    markgor  
       2022-01-15 08:53:17 +08:00
    有没有可能:
    GET bookinfo-->缓存静态信息
    GET bookOrderInfo --->缓存静态信息
    POST bookorderInfostatus ---> 实时状态信息。
    为了方便做数据缓存?

    >token 登录态,如果快过期了,提供了个刷新 token 的接口给前端,喊前端发现 token 要过期了就去刷一下接口
    这个我觉得没问题啊,你请求里的 token 过期了,你去刷新一下这个 token ,有什么问题呢?而且刷新后 token 值也不同了,后端也无法帮你替换成新的 token 值啊,而且这个你请求拦截时检查下不就好了?
    IvanLi127
        118
    IvanLi127  
       2022-01-15 09:18:56 +08:00 via Android   ❤️ 1
    后端的问题,如果你们只分前端和后端,并且人手比例正常,后端是要 BFF 的。除非 bookinfo 只有二三十条,前端查询出来缓存用,不然肯定要后端关联查询的。
    IvanLi127
        119
    IvanLi127  
       2022-01-15 09:22:10 +08:00 via Android
    token 过期,前端调完接口后发现过期,然后重新获取 token 。这个我个人认为没问题,有的时候是分 access token 和 refresh token 的。这样设计方便后续搞这个。
    24bit
        120
    24bit  
       2022-01-15 09:49:03 +08:00
    我们之前有类似的情况,拆分了微服务,然后又比较懒,直接在 rpc 服务上定义了前端需要的接口,通过网关做了协议转换。

    后来是有一个聚合 http 服务来单独提供前端需要的接口。
    neptuno
        121
    neptuno  
       2022-01-15 09:51:19 +08:00
    肯定不是懒,,懒的做法就是一个接口返回给你所有信息。订单状态不用单独接口,其他还行,就看业务有没有到这个程度了。
    neptuno
        122
    neptuno  
       2022-01-15 09:54:15 +08:00
    如果都放一个接口,最终这个接口就会越加越多。最终就变成一个几万行 json 的接口(前公司现状)。导致 c 端用户体验极差。如果是 B 端,低频接口确实可以聚合,但最终都会拆分
    coreki
        123
    coreki  
       2022-01-15 09:59:11 +08:00
    现在基本都是 access token + refresh token ,access token 过期,前端刷新,获取新 token ,正常操作
    zhaomeicheng
        124
    zhaomeicheng  
       2022-01-15 10:20:16 +08:00
    果然,全世界的后端...
    charlie21
        125
    charlie21  
       2022-01-15 10:25:05 +08:00   ❤️ 1
    @chtcrack #62 睁眼说瞎话
    Gaays
        126
    Gaays  
       2022-01-15 10:28:39 +08:00
    我这边也有遇到类似的情况,有多个接口而且是关联关系,想问一下大家如何处理网络请求问题,比如说网络中断,这里每个网络请求都用 try catch 来处理?多个接口多个 try catch ?因为不同接口阶段出现网络中断要报不一样的提示信息?这样处理合适吗
    WilliamYang
        127
    WilliamYang  
       2022-01-15 11:10:48 +08:00
    我这里反对部分想偷懒的前端,总有些前端想要什么东西都一下子全塞进一个接口返回,直接渲染就好了
    expkzb
        128
    expkzb  
       2022-01-15 11:19:33 +08:00
    放心,运维大哥会出来骂娘的。
    markgor
        129
    markgor  
       2022-01-15 11:26:38 +08:00   ❤️ 1
    @charlie21 #125 实际项目往往都会出现他说的那种场景;
    一开始数据量小的时候,订单详情一个接口就把数据跑出来了,大家都方便。
    数据量大了的时候,汇聚的接口返回 JSON 大小几百 KB ,开启 GZIP 的情况下,后端负载还算可以,但前端浏览器已经卡成狗了。
    这个时候就需要拆分接口,先出列表,然后用户点开信息的时候,分开加载。
    这种场景我遇到过两次,

    一次是产品列表,
    productList
    |--spuList
    |----skuList
    开始的时候是分页返回 10 条 productList,里面汇聚了 spuList 和 skuList 的信息;
    但对接某平台后,单个产品有几十个的 spu ,一个 spu 里有上百个 sku 。
    浏览器直接崩溃,后来拆分接口,productList & spuList 汇聚 skuList 单独查询。

    另一次是订单详情,
    orderInfo
    |--orderList
    |----.....
    |--personList
    |---....
    |--orderLog
    |---....
    |--payLog
    |---....
    |--.....
    主订单包含一堆子订单,子订单关联不同的供应商,订单操作日志和财务信息等。
    和上面一样,一开始都是把这堆信息打包到 JSON 里一次加载出来,
    但实际使用后,由于 personList 和 orderList 是可以修改的,导致每次修改后都要重复载入,
    最后只能才分开各自一个接口,哪一块操作后就加载哪一块的数据。
    后期供应部分还对接的第三方平台,线上发单后的结果是异步返回的,所以针对供应状态也独立一个接口进行查询。

    业务上线后,改动居多的都是前端部分,后端不可能因为“方便”前端,而把自己也“耗”进去吧。
    charlie21
        130
    charlie21  
       2022-01-15 11:47:22 +08:00
    @markgor 你这个搞法也可以,只不过如果是按一个工程的工作量分配 `工程预算` 的话:后端预算 1000 ,前端预算 10000
    rabbbit
        131
    rabbbit  
       2022-01-15 11:51:03 +08:00
    @charlie21
    事实就真跟他说的一样,往往后端都不会加接口,哪怕前端都忙疯了还要一堆接口 回调 try catch 人家照样天天喝茶.
    正常,本来人加就没义务帮你, 所以我也准备转后端了,我也想喝茶当大爷.
    dog
    rabbbit
        132
    rabbbit  
       2022-01-15 11:55:52 +08:00
    楼主这个算好的,我遇到的.
    不给你批量删除的接口,让你自己写个 for 循环删.(调 100 次吗?)
    让你提交订单, 完成订单 全走一个接口传订单状态编码的(客户端也走一个接口).

    到底是谁懒呢?
    rabbbit
        133
    rabbbit  
       2022-01-15 11:56:48 +08:00
    反正我节后是准备 run 了,不伺候大爷.
    phxsuns
        134
    phxsuns  
       2022-01-15 13:39:49 +08:00
    需要有 BFF 。否则不仅前端处理起来麻烦,原子接口直接暴露可能还会有安全问题。
    handsomehaitao
        135
    handsomehaitao  
       2022-01-15 15:25:26 +08:00
    一二没毛病 bookinfo 为什么要返回你订单信息? 三合并到二就可以了 刷新 token 你不处理让谁处理?
    markgor
        136
    markgor  
       2022-01-15 15:41:00 +08:00
    @charlie21 #130
    这些没有对错,一脚踢的情况下怎么方便怎么来;
    分前后端的话要么听架构的话,要么听项目经理的话,何必自寻苦恼;
    我觉得 LZ 的公司职能是后端支配前端部门。

    而且这些也很难说按工作量去计算。
    据我所知微信小程序部门,一个人负责一个组件(比方 button/textarea )或 api 。
    可是他们的福利也比很多公司要好 :dog
    janus77
        137
    janus77  
       2022-01-15 15:52:37 +08:00
    微服务是针对服务端内部互相调用而做的,暴露给前端的话还是统一一个接口舒服。其实就是懒,少一个接口而已
    weakish
        138
    weakish  
       2022-01-15 16:13:28 +08:00
    订单状态也拆开应该就是 @markgor 在 117 楼说的订单状态是会变的,而订单信息基本是不变的。

    后端拆细没问题(如果后面的服务确实是分开的话),前端写起来麻烦,但是好处是后端出故障的时候前端不会全挂。订单状态变动比较频繁,出问题的可能性最高,单独一个接口,那么它挂了,用户只是看不到订单状态或者看到的是可能过时的订单状态,其他功能都不影响。

    另外,如果网站要保证离线可用(包括用户的流量非常贵,要尽可能省流量),前端是要自己缓存信息的。那么这种情况下,订单状态的缓存策略和订单信息和缓存策略应该是不一样的,这种情况下,后端接口分开,前端反而好处理。
    weakish
        139
    weakish  
       2022-01-15 16:19:33 +08:00
    @rabbbit 真正的不加接口是设计良好,该有的接口都有,足够正交,易于组合(让别人可以自己折腾)。虚假的不加接口,就是凑了一堆接口就结束了,反正又不是不能用(折腾别人)。
    lolizeppelin
        140
    lolizeppelin  
       2022-01-15 17:18:57 +08:00   ❤️ 1
    后端行不行我不知道
    但 token 那个是标准做法
    这都能 bb 说明你水平不行
    leafre
        141
    leafre  
       2022-01-15 18:09:54 +08:00
    oauth2.0 token 就是这样处理,除非不用 token
    byte10
        142
    byte10  
       2022-01-15 18:30:37 +08:00
    这问题其实非常的好,其实在架构设计的时候 ,就有这个方案的选型,不管怎么样,后端肯定是需要一个数据聚合层的,因为你的这个多次查询的方案,前端体验非常的糟糕。现在就是这个聚合的逻辑放在前端还是后端的问题,其实都没有错,但是更多的是放在后端,最好统一放在后端,架构统一。放在前端其实不太好控制,尤其是 app 的发版,如果是 WEB 倒无所谓了。
    winglight2016
        143
    winglight2016  
       2022-01-16 09:24:50 +08:00
    接口设计,当业务体量小的时候,怎么搞都没问题。既然是看一本书的相关订单,那就是后台应用,没有并发压力,设计方案基本上靠 PK 解决。

    token 设计并没有问题,只是不应该前端判断“快”到期了就去刷新一下,而是 accesstoken 失效后,前端处理这个返回异常时,再用 refreshtoken 刷新一下,可以获得 accesstoken 。虽然我也觉得这么搞很麻烦,可是设计上把 accesstoken 的过期时间设置的短一些,是为了提高安全性。
    lblblong
        144
    lblblong  
       2022-01-16 11:14:52 +08:00
    这种情况我一般就把后端的三个接口包装一下,反正也多不了几行代码,公司的业务,加载快不快你管它干嘛,有人要问为什么这么慢,你就直接甩锅给后端说接口拆太多了呗
    anc95
        145
    anc95  
       2022-01-16 13:20:35 +08:00   ❤️ 1
    BFF 中间层搞起,加上前后端一体化调用,体验蹭蹭的上去了。中间层部署、前端脚手架再整点基建,可以升职加薪了,多好
    SmiteChow
        146
    SmiteChow  
       2022-01-17 10:08:56 +08:00
    无所谓对错,权责而已。要么大前端,要么小前端,看人员配比。

    大前端就上 graphQL ,小前端就求后端加接口。
    xrsylf
        147
    xrsylf  
       2022-01-17 10:18:39 +08:00
    刷新 token 这个方式现在就算不是主流,应该也是普遍使用了
    leafre
        148
    leafre  
       2022-01-17 13:36:15 +08:00
    本着谁受益谁研发原则,API 聚合(BFF)应该由前端团队研发,毕竟想要什么数据,前端自己最清楚,BFF 也减轻了前后端的沟通成本
    giiiiiithub
        149
    giiiiiithub  
       2022-01-17 14:41:14 +08:00
    聚合谁来做的问题,后端懒得做让前端做了。这后端有点懒了,api gateway 其职责之一就是组合内部服务 api 对 client 提供服务。
    4771314
        150
    4771314  
       2022-01-17 15:32:02 +08:00
    不了解具体的业务场景,但是这就是一个数据聚合的问题。
    看你们的具体模型和架构是怎样的,一般就两种:有 BFF 、没有 BFF ,有 BFF (一般是前端团队维护)的话,这部分的逻辑放到 BFF 中实现是合理的;如果是没有 BFF 这个分层,那么这份数据一般还是后端聚合,毕竟这里要是前端实现的话,接口是串行的,会影响前端页面的渲染,不是很合理。
    不过如果项目就是常见的前端-后端模型的话,那就应该打死后端(虽然我是后端 QAQ ),毕竟在这种场景中,后端是为前端服务的,如果前端的需求就是聚合后的数据,那后端需要提供聚合后的数据的。
    4771314
        151
    4771314  
       2022-01-17 15:33:33 +08:00
    token 的问题是不是登录态就解决了
    token 过期的时候,提醒用户重新登录,这也是很常见的操作了吧?
    Mrzhs
        152
    Mrzhs  
       2022-01-17 15:59:29 +08:00
    说白了就懒呗.一个数据对应后端不同的表,不愿做数据聚合
    rickiey
        153
    rickiey  
       2022-01-17 16:09:34 +08:00
    很明显,数据量太小,连分页都没有,体量不大的小公司吧,随便搞搞了,想咋弄就咋弄,出不了啥大问题,屎山上堆屎就行了,人一定要看开点
    lufer
        154
    lufer  
       2022-01-17 17:12:06 +08:00
    @lblblong
    这种情况我一般就把后端的三个接口聚合一下,反正也多不了几行代码,公司的业务,加载快不快你管它干嘛,老板要问为什么前端数据渲染这么慢,你就直接甩锅给前端说接口全聚合了呗
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2030 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 16:15 · PVG 00:15 · LAX 09:15 · JFK 12:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.