web层
```html 打开浏览器,输入一个网址,按下回车。你看到的东西——页面、按钮、输入框、跳动的动画——全部来自 web 层。这层东西离用户最近,也最容易被当成“就是前端”。但 web 层不止是前端。它是一整套跑在 HTTP 之上的逻辑:路由怎么走、状态怎么存、请求怎么发、错误怎么兜底。前端只是它露出来的那张脸。 我最早意识到 web 层独立存在,是因为一个线上 bug。用户点击“提交订单”,按钮转圈,然后页面白屏。后端日志干净,数据库没写入。查了半天,问题出在 web 层的一个中间件:它把某个 header 里的 token 截断了,长度超限,后端根本没收到有效认证。前端代码没错,后端逻辑也没错。错的是夹在中间那层——它负责转发,却悄悄改了东西。web 层就是这样,平时透明,出问题时你才发现它一直在做决策。 路由是 web 层最基础的活儿。但很多人把路由理解成“URL 匹配到哪个页面”,太窄了。路由还管权限、管重定向、管参数解析。比如 状态管理是另一个坑。前端框架流行之后,很多人把状态全塞进 Redux 或者 Pinia,觉得这样“可控”。但 web 层真正的状态是分层的:URL 里的查询参数、cookie 里的会话标识、内存里的临时数据、localStorage 里的持久缓存。它们生命周期不同,同步方式也不同。我调试过一个购物车问题:用户加了商品,刷新页面,东西没了。查下来是状态存在内存里,没写进 localStorage。但更麻烦的是,同一个商品在 URL 参数和内存里各有一份,改了一个没改另一个,界面显示的数量和实际下单的数量对不上。web 层要协调这些状态,不是选一个库就能解决的。 请求发送这块,fetch 和 XMLHttpRequest 都能用,但 web 层要考虑的不只是发出去。超时怎么设?重试几次?并发请求怎么合并?错误怎么分类?我见过一个页面,加载时同时发 12 个请求,每个都独立重试 3 次。网络一抖,浏览器直接卡死。后来改成:关键请求优先,非关键请求延迟,失败后指数退避。web 层做流量调度,跟后端做负载均衡是一个道理。只是前端开发者常常忽略这一点,觉得“发请求就是发请求”。 错误兜底最考验 web 层的成熟度。后端返回 500,前端不能只弹一个“系统繁忙”。要区分:是网络断了,还是服务挂了,还是参数错了?不同错误给不同提示,甚至不同操作。比如 401 跳登录,403 显示无权限,404 显示资源不存在,500 显示重试按钮。这些逻辑写在 web 层,用户才觉得“这个网站懂我”。我见过一个后台系统,所有错误都弹同一个 toast:“操作失败”。用户不知道是密码错了还是服务器炸了,只能反复点。web 层偷懒,用户体验就崩。 还有缓存。HTTP 缓存、Service Worker、内存缓存、CDN 缓存——web 层要决定什么该缓存、缓存多久、什么时候失效。一个静态资源,如果 Cache-Control 设成 web 层不是画界面的。它是用户和系统之间的翻译官、调度员、保安。它决定请求怎么发、状态怎么存、错误怎么报、资源怎么缓存。这些事做得好,用户感觉不到;做得差,用户骂的是“这个网站真烂”,而不是“web 层没写好”。但写 web 层的人知道,烂的从来不是界面,是界面背后那层逻辑。/user/:id 这种路径,web 层要把 :id 抠出来,校验它是不是数字,再决定是渲染页面还是返回 404。这些动作发生在页面加载之前。用户看不到,但一旦出错,就是 404 或者 500。我见过一个项目,路由写得太随意,/admin 和 /admin/ 被当成两个不同路径,结果权限校验漏了一个,普通用户能直接访问后台。web 层的一个斜杠,就是安全漏洞。no-cache,每次都要回源,慢。设成 max-age=31536000,又可能更新不了。我习惯给带 hash 的文件设长缓存,给 HTML 设短缓存。web 层管好缓存,用户打开页面就是秒开。管不好,就是白屏转圈。