
正则表达式很适合做格式校验和文本提取,却也可能把一次普通请求放大成数秒甚至更久的 CPU 计算。问题通常不在“用了正则”,而在回溯型引擎遇到含糊模式和恶意输入时,必须反复尝试大量失败路径。这类正则拒绝服务(ReDoS)值得像数据库查询一样被审查和限额。

正则表达式很适合做格式校验和文本提取,却也可能把一次普通请求放大成数秒甚至更久的 CPU 计算。问题通常不在“用了正则”,而在回溯型引擎遇到含糊模式和恶意输入时,必须反复尝试大量失败路径。这类正则拒绝服务(ReDoS)值得像数据库查询一样被审查和限额。

命令行工具不只是给人敲的快捷入口,更是脚本、CI 与其他程序会调用的小型接口。只能打印漂亮文本的命令,第二次自动化时往往就得重写;输入、输出和失败语义清晰的 CLI,则能自然接进管道,成为可靠工作流的积木。

CSV 常承载批量创建客户、更新库存和迁移历史记录等高风险动作。难点不在解析一行文本,而在表头被改名、日期格式混杂、同一文件重复上传,以及第 8 000 行失败后如何处理。把导入做成有边界、有记录的流水线,错误才可解释、结果才可追溯。

订单状态、构建日志和后台任务进度这类信息,往往只需要服务端持续推给页面。Server-Sent Events(SSE)比双向协议更轻:一个普通 HTTP 响应保持打开,浏览器的 EventSource 会在连接中断后尝试重连。但“能收到消息”不等于“稳定送达”。代理缓冲、空闲超时和重连窗口里的事件缺口,都会让页面看起来偶发失效。

两位用户同时编辑同一份资料,是后台系统里非常常见的场景。若接口只接受一个普通的 PUT 或 PATCH,后提交的请求会悄悄覆盖先提交的修改:两次都返回 200,数据却已经丢失。数据库事务能保护单条 SQL 的原子性,却不会替 HTTP 客户端判断“我编辑的还是不是刚才看到的版本”。

一次下游服务变慢,往往不会只影响一个请求:等待中的线程、连接池和重试会继续堆积,最后把原本健康的调用方也拖垮。熔断器(Circuit Breaker)不是“请求失败就拒绝”的开关,而是一套让故障隔离、恢复探测和业务降级各归其位的状态机。

页面已经打开,接口也很快,但点击筛选、展开弹窗或输入搜索词时仍会“顿一下”。这类问题经常不在服务端,而是某段同步 JavaScript 长时间占住了浏览器主线程:输入无法处理,样式和布局不能提交,下一帧也画不出来。与其凭感觉删代码,不如先记录长任务发生的时间、持续时间和业务动作,再做有证据的优化。

很多服务把 /health 写成“能响应就返回 200”。上线初期它看似足够,直到数据库抖动、连接池耗尽或进程进入假死:该重启的实例没有重启,该摘流量的实例仍在接请求。健康检查不是一盏绿灯,而是给编排器、负载均衡器和告警系统的操作信号。

业务常把“删除”理解为暂时不让用户看见,于是给表加上 deleted_at 就上线。几个月后,重复注册被唯一索引拦住、后台统计混入已删除数据、关联记录变成孤儿,恢复操作又覆盖了新数据。软删除不是一个字段,而是一套从可见性、约束到最终清理的生命周期协议。

列表接口在测试数据上很快,上线后却随着分页条数变大而变慢,常见原因不是少了索引,而是 ORM 在循环里偷偷访问关联对象:先查一页主记录,再为每条记录各发一次查询。这类 N+1 问题的危险在于单条 SQL 很快,却会放大网络往返、连接占用和数据库解析成本。治理它的重点不是“多写一个 include”,而是让一次请求的查询数量可见、可预测、可回归。