logo学习随笔

【译】前端开发人员应该知道的后端知识

March 15, 2020

对于前端开发者来说,除 API 外不需要知道其他任何后端知识就能出色的完成绝大多数的工作。如果在不同的前端工作中都有深入涉猎,那么你应该已经了解了一些必要的后端知识。以下是有关前端开发者需要知道的后端知识清单。

请求率

后端资源是有限的,只能处理确定的请求率。通常情况下,不需要关心—前端应该致力于创建良好的用户体验,后端负责优化和拓展。当前,网络请求至后端并不是免费的,并且它们不是同样的昂贵(就资源的使用来说)。

如何衡量一个请求的价值呢?据以往的经验是写入要比读取的成本高,所以改变的数据越多,成本越高。举一个简单的例子:假设我们在开发 Google docs,我们希望用户退出时不丢失任何工作内容,所以需要经常保存。那是否在每个字符插入或删除时都进行保存呢?后端服务可能不能够进行处理,或者相应的成本会因不必要的请求变得异常高。在用户停止输入后节流保存可以达到 99%的期望效果,而不需要为了 1%消耗巨大成本。

此外我们想要轮询后端来获取变更,想要获取最新的 doc 版本,那么需要多久发起一个请求呢?读取要比写入成本更低,因此可以比写入请求更多但仍然有限制。

这个限制依赖于许多因素,比如在任何给定时间的最大活动客户端数,后端基础设施和预算。如果有一个需要达到限制的变更,需要告知后端团队。否则,可能就是在对自己发起 DDoS 攻击。

宕机时间

需要做好每个后端请求在某些用户某种情况下可能会失败的准备。后端在某个时刻必然会宕机,或者对于某个接口失败而其余正常工作。需要鉴别出应用中哪些请求在失败时是紧急的,需要在整个应用之上显示稍后重试的错误信息,哪些请求时可以通过优雅的降级来保证用户体验(例如,将某功能的按钮置灰并在 hover 时提供当前不可用的错误提示)。

如果后端被拆分为了多个微服务,那么一些接口失败的可能性会更高。如果后端只是一个独立的服务器,一个单独的失败会使整个应用宕机。好的前端通常会把后端调用都包裹在 try-catch 中,并准备好异常的跳转路径。JavaScript 没有恢复能力,如果没有处理好异常,整个应用会崩溃。

HTTP

后端和前端应当使用合适的 HTTP 状态码(在一定程度上)。前端应该知道后端计划返回的每个状态。不要解析错误消息来判断登录失败,401 是更适合的。不要在收到 400 时重发请求因为大概率不会成功,而 500 状态码表明服务器异常,可能在重启,因此重试可能会成功。

其他值得了解的 HTTP 属性:

  • HTTP 请求如果花费时间太久可以被服务器关闭。如果认为某些任务可能临近限值(20 秒从经验上说相对合适的),应该从单个请求响应切换为一个轮询请求等待结果,或者采用另一种机制如 web sockets。
  • 如果发送一个非常大的数据至后端(如一个视频),应当使用 multipart 请求,可以将数据分为多块来发送。
  • 有时意外的发生是由于 URL 的长度限制。一些前端的请求是通过 query 传参数到后端的,但如果传入超过 2048 个字符,应当把数据编码通过 body 发送请求。

分发业务逻辑

如果一些功能的业务逻辑可以在前端或后端来实现,通常应该在后端来实现。原因如下:

  1. 后端的变更会更快 — 一次部署至所有服务器,过时的业务逻辑消失,但是前端客户端是在用户这边,一次部署不意味着在生产环境中已经不存在已经失效的业务逻辑在运行。
  2. 如果业务逻辑需要计算能力,它很难测试客户运行的机器的能力范围。如果你只在公司提供的 Mac pro 上测试性能,那么就不会意识到$100 的 Chromebook 在计算时会多么慢。
  3. 在后端实现业务逻辑更加保密。比如有一个功能只允许 pro 级用户访问,如果只在前端混淆后限制,有些人可能会通过其 API 调用返回的数据来进行反向工程,然后访问其功能。这在现实中广泛存在(如绕过限制的音乐播放器)。

跨域请求

作为一个安全协议,如果一个请求指向后端不同的域名,它会因为是“跨源请求”而被拒绝。这被称为“同源策略”。这在开发中就会遇到,因为目前都是前端通过 NPM/Yarn 来启动前端服务器,而后端在另一个端口上,所以每个请求都是跨域请求。

解决方案:

  • 在开发环境 host 中配置映射服务器的域名
  • 在服务端通过增加判断在开发中开启,生产环境关闭的条件来运行跨域访问
  • 白名单中增加开发环境域名

跨站请求伪造是一种用户在其他网站发起的未鉴权的请求而发起的攻击。如,在某个网站点击了一个按钮,它执行了 JavaScript 代码去尝试使你在你的银行网站执行一个请求。为了阻止攻击,服务器会为每次会话提供一个一次性的口令,所以这个请求会由于没有口令而失败。这被称为 CSRF 口令。将它附在头部来验证请求。

缓存清除

每个请求发送至后端时会经过多重缓存。如果首次访问一个网站,等待它加载,然后重载页面,该页面会比首次加载会更快原因是浏览器缓存了一些资源如 favoritewebsite.com/static/script.js。如果想要改变 script.js 那么可以改变文件名,在 index.html 中把 script.js 变为 script.js?v=2,因为没有后续的其他请求,那么已缓存的 script.js 就变得不相关(除非 index.html 也被缓存,对于 index.html 的请求应当在后端处理为不缓存)。现代化的构建流水线每次构建都包含缓存清除,就像一些 JavaScript 文件名看起来 script.4e885f13.js。通常这只会应用于样式文件和脚本,但也可以应用到图片和其他资源。一些资源通常不会频繁改动,那么最好不要做自动缓存过期处理,只在需要更新时手动替换即可。

参考

https://terrastruct.com/blog/what-frontend-engineers-should-know-about-backend/