关于技术探索与实践的一些经验:一个文科转码仔的血泪史
大家好,我是小林,一个非科班出身、靠自学杀入前端圈的“伪程序员”。大学读的是汉语言文学,毕业时连 console.log 是干啥的都不知道。如今在一家中型互联网公司做前端开发,刚入职两个月,天天在 Mac 上敲代码(Windows?那是我拿来测兼容性的“刑具”)。虽然岗位是前端,但因为之前跳槽前被 K8s 和云原生疯狂毒打过一轮,现在团队里一提到部署、CI/CD,大家都会弱弱地问一句:“小林,你懂这个不?”
今天写这篇,不是为了炫技——毕竟我离“大神”还差八百个 LeetCode Easy 题——而是想聊聊最近两个月里,在真实项目里踩过的坑、熬过的夜,以及那些让我半夜惊醒的 面试题挑战 和 开发心得。如果你也和我一样,半路出家、内心忐忑、总觉得自己是个“冒牌货”,那咱们一起抱团取暖。
起因:产品经理说“我们要上线一个实时看板”
事情要从三周前说起。那天下午四点,产品同学拎着一杯瑞幸走进我们工位区,笑眯眯地说:“兄弟们,双十一大促快到了,老板想要一个实时数据看板,展示每分钟订单量、用户活跃度这些,要酷炫、要流畅、要能扛住流量峰值。”
我:???
我们组是典型的“小前端+大后端”配置,前后端分离做得比较彻底。按理说,这种需求应该是后端推数据,前端渲染就行。但问题来了:后端用的是传统 HTTP 轮询,延迟高、压力大,而且双十一那天服务器能不能扛住都是未知数。
更致命的是——我们没有 WebSocket 服务。
当时我的第一反应是:“这不归我管吧?”
但转念一想:如果我不顶上,可能就得等后端排期,而 deadline 就在两周后。再加上我之前为了跳槽,硬啃了 Kubernetes、Docker、Nginx Ingress,甚至自己搭过一套基于 Server-Sent Events(SSE)的 demo……于是,鬼使神差地举手:“要不……我试试用 SSE 或 WebSocket 搞个轻量级方案?”
领导眼睛一亮:“可以啊!你不是说你熟悉云原生吗?正好练练手。”
我:完了,又把自己卖了。
探索:从“我觉得很简单”到“我裂开了”
一开始,我信心满满。不就是长连接嘛?Node.js 写个 WebSocket 服务,前端 new WebSocket() 连上去,onmessage 接数据,react 渲染一下,搞定!
结果第一天就翻车。
坑1:K8s 的 Service 网络策略把我整懵了
我在本地用 ws://localhost:3001 测试一切正常。但一部署到测试环境(K8s 集群),前端死活连不上 WebSocket 服务。Chrome 控制台报错:
WebSocket connection to 'wss://realtime-api.our-company.com/' failed: Error during WebSocket handshake: Unexpected response code: 502
我:???502?难道是 Nginx 配置不对?
查了 Ingress 配置,发现我们用的是 AWS ALB Ingress Controller,而它默认不支持 WebSocket 升级头!需要显式添加注解:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: realtime-ingress
annotations:
alb.ingress.kubernetes.io/group.name: "frontend-group"
alb.ingress.kubernetes.io/load-balancer-attributes: routing.http.drop_invalid_header_fields.enabled=true
# 关键!允许 WebSocket 升级
alb.ingress.kubernetes.io/backend-protocol-version: GRPC # 不对,这是 gRPC 的...
错了错了!正确做法是确保 ALB 能透传 Upgrade 和 Connection 头。最终配置如下:
annotations:
alb.ingress.kubernetes.io/backend-protocol: HTTP
# 必须显式设置监听器支持 WebSocket
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
但其实真正起作用的是——在 ALB 的目标组里启用“粘性会话”,并且确保后端 Pod 能处理长连接。折腾了整整一天,终于连上了。那一刻,我差点给 ALB 跪下。
📌 开发心得:别以为“云原生=开箱即用”。K8s 抽象了基础设施,但也隐藏了网络细节。当你用 WebSocket、gRPC、SSE 这类协议时,Ingress Controller 的能力边界必须搞清楚。否则,你写的代码再漂亮,也过不了网关那一关。
坑2:前端自动重连逻辑写得像一坨💩
连通之后,我以为万事大吉。结果测试同学一压测,前端页面卡死,控制台疯狂报错:
WebSocket is already in CLOSING or CLOSED state.
原来,当网络抖动或服务短暂不可用时,WebSocket 会断开,但我没做重连。于是赶紧补了一个“指数退避重连”逻辑:
class ReconnectableSocket {
private url: string;
private maxRetries = 5;
private currentRetry = 0;
private socket: WebSocket | null = null;
constructor(url: string) {
this.url = url;
this.connect();
}
connect() {
this.socket = new WebSocket(this.url);
this.socket.onclose = () => {
if (this.currentRetry < this.maxRetries) {
const delay = Math.pow(2, this.currentRetry) * 1000; // 指数退避
console.warn(`Reconnecting in ${delay}ms...`);
setTimeout(() => {
this.currentRetry++;
this.connect();
}, delay);
}
};
this.socket.onopen = () => {
this.currentRetry = 0; // 重置重试次数
};
}
}
但!这还不够。因为 React 组件卸载时,如果没清理 WebSocket 实例,会导致内存泄漏,甚至多个实例同时连接。
最后加了个 useEffect 清理函数:
useEffect(() => {
const ws = new ReconnectableSocket('wss://...');
return () => {
ws.close(); // 确保组件销毁时关闭连接
};
}, []);
📌 面试题挑战:你知道 WebSocket 断线重连的最佳实践吗?
别光说“重连”,要答出:退避策略、最大重试次数、连接状态管理、资源清理。这题我在上家公司面试就被问过,当时支支吾吾,现在总算能答得像个样子了。
技术选型:为什么最后用了 SSE 而不是 WebSocket?
折腾完 WebSocket,我发现一个问题:我们的场景其实是单向数据流——后端推数据,前端只读不写。而 WebSocket 是双向的,维护成本高,且需要额外的心跳机制防超时。
于是,我大胆提议:换成 Server-Sent Events(SSE)。
SSE 的优势:
- 基于 HTTP,天然穿透防火墙和代理
- 自动重连(浏览器原生支持)
- 轻量,无需额外协议
- 与 K8s + Nginx 兼容性极好
后端只需返回 text/event-stream,前端用 EventSource 监听:
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
// 更新状态
};
// 自动重连!浏览器帮你处理了
部署时,只需在 Nginx 配置中关闭缓冲:
location /api/stream {
proxy_buffering off;
proxy_cache off;
proxy_pass http://backend;
}
上线后,资源占用比 WebSocket 低了 40%,稳定性反而更高。运维大哥都夸我“懂事”。
| 方案 | 连接建立 | 重连机制 | 协议复杂度 | K8s/Nginx 兼容性 | 适用场景 |
|---|---|---|---|---|---|
| WebSocket | 手动 | 需自实现 | 高 | 中(需调优) | 双向通信(聊天、游戏) |
| SSE | 自动 | 浏览器原生 | 低 | 高 | 单向推送(通知、看板) |
📌 开发心得:不要为了用新技术而用新技术。业务场景决定技术选型。有时候,老掉牙的 SSE 比时髦的 WebSocket 更合适。
总结:文科生的生存之道
这两个月,我从一个“只会写 div 的前端仔”,被迫成长为能和运维聊 Ingress、和后端谈协议、和产品讲技术边界的“杂食动物”。过程中崩溃过、自闭过,甚至一度怀疑自己是不是该回老家考编。
但每次搞定一个线上 Bug,每次听到测试说“这次没崩”,每次 PR 被同事点赞,那种成就感,真的会上瘾。
给和我一样的转码朋友几点建议:
- 别怕暴露无知:我入职第一周就问“Pod 和容器啥区别”,没人笑话我,反而耐心解释。
- 把面试题当实战题:很多面试题(比如重连、缓存、性能优化)其实就是日常会遇到的问题。提前准备,等于提前避坑。
- 善用你的“非科班视角”:文科生往往更擅长沟通、文档、用户体验。技术只是工具,解决问题才是目的。
- Mac 很香,但别忘了 Windows 测试:上周我就因为没测 Edge,导致 CSS Grid 布局错乱,被 QA 吊着打 😭
最后,送大家一句我贴在显示器上的话:
“你不是不够格,你只是还在路上。”
共勉。

评论 0