关于技术探索与实践的一些经验:一个文科转码仔的血泪史

测试环境炸了
2025-12-12 19:03
阅读 339

大家好,我是小林,一个非科班出身、靠自学杀入前端圈的“伪程序员”。大学读的是汉语言文学,毕业时连 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 能透传 UpgradeConnection 头。最终配置如下:

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 被同事点赞,那种成就感,真的会上瘾。

给和我一样的转码朋友几点建议

  1. 别怕暴露无知:我入职第一周就问“Pod 和容器啥区别”,没人笑话我,反而耐心解释。
  2. 把面试题当实战题:很多面试题(比如重连、缓存、性能优化)其实就是日常会遇到的问题。提前准备,等于提前避坑。
  3. 善用你的“非科班视角”:文科生往往更擅长沟通、文档、用户体验。技术只是工具,解决问题才是目的。
  4. Mac 很香,但别忘了 Windows 测试:上周我就因为没测 Edge,导致 CSS Grid 布局错乱,被 QA 吊着打 😭

最后,送大家一句我贴在显示器上的话:

“你不是不够格,你只是还在路上。”

共勉。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝