|
```html 浏览器里点一下按钮,后端服务器那边就得把数据吐回来。数据这事儿听起来简单,交互但中间隔着一整条HTTP请求-响应链,后端每一环都有坑。数据 前端发请求,交互最原始的后端方式是XMLHttpRequest。现在基本都用fetch或者axios。数据拿fetch举例,交互你写fetch('/api/user'),后端浏览器就帮你拼一个GET请求出去。数据但很多人不知道,交互fetch默认不带cookie,后端跨域时得手动加credentials: 'include',数据不然后端session拿不到,交互用户状态直接丢失。我见过一个项目,登录接口返回成功,但后续请求全401,查了一下午才发现是这个参数漏了。 请求发出去,先经过DNS解析、TCP握手、TLS加密(如果是HTTPS),然后才到后端服务器。这中间任何一个环节出问题,前端只能看到一个笼统的Network Error。真实场景里,用户网络抖动、公司代理拦截、证书过期,都可能导致请求根本到不了后端。所以前端做错误处理,不能只判断response.status,得区分“请求没发出去”和“发出去了但服务器返回错误”。 后端收到请求,第一件事是解析。以Node.js的Express为例,app.use(express.json())这行中间件负责把请求体里的JSON字符串转成对象。如果前端发的是Content-Type: application/json但body格式错了,比如多了个逗号,Express直接抛400,前端拿到的是HTML错误页而不是JSON。这时候前端如果无脑response.json(),就会再抛一个解析异常,把真正的错误信息盖掉。我习惯在fetch后面先await response.text(),看看到底返回了什么,再决定要不要JSON.parse。 数据从后端出来,通常要经过序列化。Java的Spring Boot默认用Jackson,把对象转成JSON。这里有个经典问题:日期格式。LocalDateTime默认序列化成"2024-01-15T10:30:00",前端new Date()解析时区可能差8小时。解决办法要么后端加@JsonFormat指定时区,要么前端用dayjs手动处理。没有银弹,得看团队约定。 跨域是绕不开的。浏览器同源策略限制下,前端跑在localhost:3000,后端在localhost:8080,请求能发出去,但响应会被浏览器拦截。后端加Access-Control-Allow-Origin头是标准做法。但有个细节:如果请求带了自定义头比如Authorization,浏览器会先发一个OPTIONS预检请求。后端必须正确响应这个OPTIONS,返回Access-Control-Allow-Headers,否则真正的POST根本不会发出。很多新手只配了Allow-Origin,然后纳闷为什么POST请求在Network面板里显示OPTIONS且状态是204但后续没动静。 数据格式的选择也有讲究。JSON现在是绝对主流,但遇到文件上传就得用multipart/form-data。前端用FormData对象,后端用multer(Node)或MultipartFile(Java)接收。这时候Content-Type不能手动设,浏览器会自动加boundary。如果你手贱写了headers: { 'Content-Type': 'multipart/form-data'},boundary丢失,后端解析直接失败。这个坑我踩过两次,后来学乖了,传文件时fetch的headers里什么都不写。 安全方面,前端永远不能信任后端返回的数据。后端说{ isAdmin: true},前端就显示管理按钮?不行。权限判断必须后端做,前端只负责展示。同样,后端也不能信任前端传来的任何东西。用户ID、价格、数量,全都要在服务端重新校验。见过一个电商项目,前端把商品单价放在请求体里传给后端,后端直接存库。结果有人用Postman改价格,一块钱买走了iPhone。 最后说个实际观察:很多团队前后端联调时,接口文档写得很漂亮,但字段类型对不上。后端返回id: 123(数字),前端TypeScript定义成id: string,运行时不会报错,但id === '123'永远为false。这种问题在测试环境数据少时发现不了,上线后用户ID超过某个范围才暴露。所以我现在坚持用zod或io-ts在运行时校验接口返回,宁可多写几行代码,也不想半夜被叫起来查bug。 ``` |