101
iseki 331 天前 via Android
不要尝试兼容,否则后患无穷,严格校验数据,出错就报 bug 让后端改。一旦提到兼容,你很难定义清楚兼容的边界,到时候指不定出什么幺蛾子。
@bianhui 反爬应该用工程手段解决,而不是让人直接在代码里写 abcd 。至于你说的第二个问题,接口和内部实现无关,不应因为内部实现影响接口,这点对前后端都一样。 |
102
iseki 331 天前 via Android
当然命名风格还是应该尽量统一一下,不要同一个接口都混合不同的命名风格。
|
103
iseki 331 天前 via Android
此外后端如果不是 bff ,你不能要求它完全按照前端页面设计,这 API Web 前端用完了客户端可能还得用呢,不是说你展示在一个地方后端接口就一定是一个字段,前端该做的事不能偷懒。
|
104
petergui 330 天前
null , nil ,undefined , [key1:val1],"" , "bool".
ToB : graphQL,BFF 中间层,把使用到数据掌握到自己手上,也方便。 ToC: openapi 过一遍最多了。 看人。一般是在 response 上做 callback 适配。 业务紧,时间紧,人员紧。要求不了太多。业务的上游,实现迭代的下游。 以和为贵。人熟好办事。 |
105
leokun 330 天前
前端能兜住杂乱的数据也是一种本事
|
106
ruxuan1306 330 天前 2
我看之前楼层都在情绪输出,我来说说我的思考吧。
两个前提: 1. 老板只在意业务功能是否实现,没人在意前后端之间的接口质量; 2. 督促后端交付高质量接口的沟通成本远大于前端写几行 map 的开发成本; 故结论,前端兼容。 问题是,对于前端的某一字段,不同的后端提交、响应不同,甚至值的类型也不同。 导致在写 TypeScript 时,就要定义大量 TS 类型,还很难起名。 但仔细想想我们真的需要这些“一次性”类型吗? 看个例子,假设我们有两个接口: ```JavaScript // id 查 user const res = fetch.get('/user', { id: 1 }) console.log(res.body) // { id: 1, name: 'alice' } // id 改 user 名 const res = fetch.post('/user', { user_id: '1', new_username: '' }) console.log(res.body) // { code: 1 } ``` 很难受吧,查和改的字段居然不一致。 那我用户 ID 究竟叫 id 还是 user_id ?类型究竟是 number 还是 string ? 很简单,按前端方便来: ``` type User = { userId: string, username: string } <div> <div>用户 ID:{{userId}}</div> <div>用户名:<input type="text" value="{{username}}" /></div> </div> ``` ??? 因为 JavaScript 里常用驼峰命名,userId 通常也只是展示,不会涉及什么数值运算,绑定 input 之类也比较方便… 噢,哈哈,你肯定早就知道这些,我知道你是在疑惑,接口怎么办? 别急。 我们知道,TypeScript 类型系统很好很强,除非 any 泛滥。 要想抑制 any 渗入 TS ,就要观察 any 从哪产生: 什么函数返回 any ? - JSON.parse() - fetch() - ... 喔,外部数据流入 TS 时,就是 any ,有才有德的我知道,此时我应该立刻手动为标记类型: ```JavaScript // 接口响应类型 type GetUser = { id: number, name: string } // 前端易用类型 type User = { userId: string, username: string } function fetchUser(userId: string) { // 外部数据 const res = fetch.get('/user', { id: Number(userId) }) console.log(res.body) // { id: 1, name: 'alice' } // 标记类型 any -> GetUser const data: GetUser = res.body // 转为前端易用的格式 const user: User = { userId: String(data.id ?? ''), username: data.name } return user } ``` 很好很完美,我们成功封装了一个接口请求函数,它能通过 string 的 userId ,查到 User 数据,以前端想要的格式。 但多看一眼,我们真的有必要定义 GetUser 吗? 简化下可以吗: ```JavaScript type User = { userId: string, username: string } function fetchUser(userId: string): User { const res = fetch.get('/user', { id: Number(userId) }) return { userId: String(res.body.id ?? ''), username: res.body.name } } ``` 噢,虽然 res.body 是 any ,虽然按照 TypeScript 最佳实践我应该马上声明它的类型,但事实上,完全可以将这个明晰 any 的过程延迟到数据转换一并进行。 这样一切就变得简单多了,只要我守好数据流入和流出的关口,那无论多离谱的后端,我都不需撕逼,分钟对接: ```JavaScript function updateUser(userId: string, username: string): boolean { const res = fetch.post('/user', { user_id: Number(userId), new_username: username }) return res.code === 1 } ``` 于是作为前端: 在开发阶段,我以最舒适的姿势定义 State 的数据结构、绑定 UI 组件。 在联调阶段,我直接对着浏览器抓包的响应体,实现关口函数内的转换。 完全摆脱各接口字段定义不一致、实际响应和接口文档不符、string 和 number 类型没对上之类来回沟通筋疲力尽的鸡零狗碎。 再温故一遍: 1. 老板只在意业务功能是否实现,没人在意前后端之间的接口质量; 2. 督促后端交付高质量接口的沟通成本远大于前端写几行 map 的开发成本; |
107
ruxuan1306 330 天前
粘出来格式不好看,原文来自: https://zexi.notion.site/b9f941b097054bb1a28de1de61535adf
|
108
phpfpm 330 天前
保留现场,闪退,避免带来更多问题
|
109
Quarter 330 天前 via iPhone
@bianhui 你说出这话真的已经工作过了吗?你们团队都没有项目负责人和技术负责人的么,都没有人把控项目把控技术的人,这不叫道德绑架,因为你个人能力问题导致增加别人工作量我当然可以拒绝或者向上反馈提出意见,如果你个人确实因为能力不满足工作需要的话团队会做出合理的决策,我不知道你们的团队到底是多小多随意,但是我建议你也多出去看看,不少正规的公司正经的团队还是对于技术有要求的,也有明确的管理规范,想想到底是谁在抬杠,而且从你这种觉得给别人增加工作量也无所谓的所谓做人准则,我个人建议您这边也抬高一下自己的要求,别人一般都是考虑怎么不给别人添麻烦,所以也别侃侃而谈教别人做人
最后,我根本没必要道德绑架谁,我只是在讲述自己观点,你可以有自己的想法和思路,至于最终能力如何、工作态度如何,你现在以及以后的团队会给出一个符合情况的评价的,多说无益 |
110
fy1006 330 天前 via iPhone
前端拿到原型后自行抽象对象结构数据模型的人少,如果这样做了就会有一层转换层。
|
111
Quarter 330 天前 via Android
@ruxuan1306 并没有情绪输出,合理反驳,大家有方案的也可以说,老板也确实不在意具体代码质量,只是说大家工资差不多甚至前端工资更低,并不能接受后端只是从懒的角度莫名其妙给别人增加工作量,如果确实有合理解释也行,除此以外,你可能会低估这些工作量,或许几行 map 并不能搞定工作量,而且越觉得我再加几行、我再加几十行、我再加几百行就能解决,那只会越加越多,反正你都会接,最后搞不定反正也都是前端问题,反馈团队 leader ,如果团队也不作为,那就跑路吧,除非老板给了更多的工资,不然研发的地位已经够低了,没必要在研发里前端还自立一个地位最低
|
112
twofox 330 天前
|
113
kneo 330 天前 via Android
有些人,自己做不到写优秀的代码,还有脸喷别人“没受过社会毒打”“太理想化了”“那么规范干嘛”“不能要求别人”。一副劣币嘴脸。幸好只是网上相见。这辈子不会和你们共事。这种人要敢来我公司就一个字:滚。
|
114
vczyh 330 天前 via iPhone
要不就开发前讨论定好,要不就适配,不能太理想化了
|
115
vczyh 330 天前 via iPhone
还有就是老项目就是这样,很难保持一种风格
|
116
LLaMA2 330 天前
|
117
rabbbit 330 天前
专门搞一个 api 文件夹放各种接口请求,然后:
这样无论他的 api 怎么变动,都有一个中间层来轻松适配。 大概是这样吧,好久没写 ts 了 interface foo { id: string; } const getFoo = async (): Promise<foo> => { const resp = await fetch('/api/foo').then((response) => response.json()); resp.id = resp.user_id; return resp; } export { getFoo } |
118
rabbbit 330 天前
中间的那个 resp 就让它 any 吧,没必要管
|
119
0xLittleFi 330 天前
前端内部一套定义,从后端取值的时候防腐一层,后端很多时候取其他领域的数据也是这么做的。自身稳定,不稳定的交给防腐层做。
|
120
iseki 329 天前
@ruxuan1306 你这样搞百害无一利啊,今天兼容了,明天又变样了你兼容不兼容,某日几种模式冲突了你怎么办,屎山多了你糊出 bug 了怎么办。这种接口本来就一挺简单的事,从源头把问题都解决了对大家都好
|
121
Perolong 329 天前
这其实就不是方法对不对的问题,一味的妥协做兼容迟早会出事,不管是前还是后
|
122
mouyase OP @rabbbit 其实我们也想做类似的兼容,但是有时候还会出现不同的有的数据 userid 和 id 是相同的但是有的是不同的类似情况,直接盖过去有时还会有问题。
|
123
mouyase OP @ruxuan1306 好文,值得学习和思考
|