Skip to content

前端和后端

打开一个网站,屏幕上看到的所有东西——按钮、表格、图表、动画——都属于前端;但保存数据、查询列表、做计算这些"重活",前端干不了,要交给后端。前端和后端是两套完全不同的代码,跑在不同的地方,通过 HTTP 接口通信。

排查问题的时候,前端后端是两套完全不同的思路:页面点了没反应,先看浏览器控制台有没有报错、Network 面板里请求发出去没有;接口 500,直接去后端日志里捞对应的 trace id;接口明明返回 200 但页面数据是空的,大概率是字段名前后端没对齐——这种情况最迷惑,因为看起来"没错"但功能就是坏的。

一、前端

前端说白了就是浏览器里跑的那部分。涉及的技术就三种,各管一摊:

  • HTML 管页面结构——页面上有哪些元素、元素之间什么层级关系
  • CSS 管样式——颜色、字体、布局、动画、响应式
  • JavaScript 管交互——点击事件、表单提交、调接口、动态更新 DOM

举个例子,页面上一个"删除"按钮能正常工作,背后要满足几件事:HTML 里有这个按钮元素,CSS 没把它 display:none 隐藏掉,JavaScript 给它绑了点击事件,点击触发的接口请求正常返回,返回之后 JS 还要把这行数据从表格里移除。任何一步断了,用户看到的现象都是"点了没反应"。

前端源码写完之后要打包——React/Vue 的 JSX/Vue 文件不能直接跑,要先编译成普通 JS,CSS 也要压缩,最后产出一堆静态文件:index.html 加上 assets/ 下面的 JS、CSS、图片、字体。这些文件可以放 Nginx、对象存储(OSS/S3)或者 CDN,反正都是静态文件,谁都能托管。

二、后端

后端服务跑在服务器上(虚拟机、容器、Kubernetes Pod 都行),主要干四件事:接收 HTTP 请求、处理业务逻辑、访问数据库或者其他服务、返回结果。用什么语言写都行——Python 的 FastAPI/Django、Java 的 Spring Boot、Go 的 net/http、Node.js 的 Express——本质都是监听一个端口,等请求进来,然后处理。

后端代码里常见的几个对象:

  • 路由:把 URL 路径跟处理函数对应起来,比如 /api/usersget_users() 函数
  • 处理函数:具体干活的代码,读参数、做业务、查数据库、返回 JSON
  • 模型(Model):描述业务对象或者数据库表,比如 User 对应 users
  • 数据库连接:管理到 MySQL、PostgreSQL、Redis 的连接池
  • 中间件:横切关注点,认证、日志、跨域(CORS)、异常处理、限流这些都属于中间件

后端程序一般监听一个端口,比如 8080。但公网用户不会直接访问这个端口——中间隔着 Nginx、负载均衡或者 API 网关。原因是直接暴露后端端口有一堆问题:没有 HTTPS 卸载、没有认证统一入口、没有限流熔断、IP 暴露有安全风险。所以正常架构里后端端口只在内部网络可达,外部通过入口层转发进来。

三、JSON

前后端分离之后,后端返回的几乎都是 JSON。一个典型的接口响应长这样:

json
{
  "items": [
    {"id": 1, "name": "巡检 web-01", "status": "success"},
    {"id": 2, "name": "备份 mysql-01", "status": "running"}
  ],
  "total": 2
}

前端拿到之后,用 items 渲染表格,用 total 算分页。这就要求后端返回的字段名、类型、结构必须稳定——前端代码是按约定的字段名写死的,后端改一个字段名,前端这边就读不到了。

字段没对齐是个非常隐蔽的坑。比如后端返回的是 task_status,前端代码读的是 status,接口状态码 200,Network 里看响应也有数据,但页面上"状态"那一列是空的。这种问题光看监控根本发现不了,得对着响应 JSON 和前端代码逐字段比对才能定位。所以接口契约很重要,后端改字段一定要提前跟前端打招呼,或者用 GraphQL/Protobuf 这种强约束的方案。

四、前后端分离部署

把前端和后端分别部署到不同的地方,有它的道理:

浏览器第一次打开网站,先从 CDN/Nginx 拉 index.html 和 JS/CSS 文件——这些是静态资源,放 CDN 上全球加速,放 Nginx 上本地直出,反正没必要走后端。JS 跑起来之后,再去调后端 API 拿动态数据。这样一个页面可能同时访问两个域名:static.example.com(静态资源)和 api.example.com(接口),各自走各自的链路,扩展和优化都方便。

内容通常放在哪里
前端静态文件Nginx、对象存储、CDN
后端 API虚拟机、容器、Kubernetes
数据库云数据库、自建集群
入口层Nginx、API 网关、Ingress

五、跨域

浏览器有个安全策略叫同源策略——如果两个 URL 的协议、域名、端口有任何一个不一样,就视为"不同源",JS 默认不能跨源读响应。比如 https://console.example.com 的页面去调 https://api.example.com 的接口,域名不一样,浏览器会按跨域处理。

跨域不是网络层的问题,是浏览器单方面加的安全限制——后端其实已经正常处理了请求、返回了数据,但浏览器看到响应头里没有 Access-Control-Allow-Origin,就直接拦住 JS 不让它读。所以跨域问题排查时,Network 里能看到请求是 200,但 JS 拿不到数据,控制台报 CORS 错。

解决办法是后端在响应里加 CORS Header,告诉浏览器"这些源是允许的"。涉及非简单请求(比如 POST JSON)时,浏览器还会先发一个 OPTIONS 预检请求问后端"我能不能发"。所以跨域排查要看的几个东西:OPTIONS 请求的响应有没有 Access-Control-Allow-Origin、允许的方法包不包含你要用的、允许的 Header 包不包含你自定义的。少一项都会被浏览器拦。

六、联调排查

把前面讲的层都串起来,联调时遇到问题根据现象定位:

现象大概率问题在哪
接口返回 401Token 没带、Cookie 没传、登录态过期
接口返回 404API 路径写错、网关没转发、后端路由没注册
接口返回 500后端代码异常、数据库连不上、下游服务超时
接口 200 但页面空白字段名对不上、数据结构变了、前端渲染逻辑有问题
控制台 CORS 报错后端跨域配置缺字段,或者 Nginx 把 CORS Header 吃掉了
JS 文件 404前端构建路径变了、静态资源发布到了错误目录、CDN 缓存了旧路径

记住一个排查顺序:先看 Network 面板(请求发出去了吗?响应是多少?),再看后端日志(请求有没有到后端?报了什么错?),最后看代码(字段对得上吗?路由配置对吗?)。这套流程跑下来,前后端联调的问题基本都能定位到具体某一层。