PCHelper

背景介绍 腾讯体育的个人直播业务中,主播开启比赛陪看直播一直仅支持移动端开播。然而,移动端开播存在屏幕尺寸过小、摄像头拍摄角度受限等问题,严重影响了主播的解说体验。为了提升主播在比赛解说场景下的使用体验,同时降低使用 OBS 进行运营的人力成本,我们决定在腾讯视频 PC 开播助手的基础上进行迭代开发,新增对腾讯体育比赛陪看功能的支持。 选择陪看比赛界面: 陪看解说画面: 从零开发一款 PC 开播软件的成本较高。幸运的是,腾讯视频已经拥有一款成熟的 PC 开播助手,用于支持主播或艺人在 PC 端进行直播。虽然当时该产品尚不支持陪看直播功能,但我们可以在其基础上进行二次开发:接入腾讯体育的账号体系,并新增比赛陪看能力,从而以最小的开发成本实现业务需求。 整体架构概览 腾讯视频 PC 开播助手基于 Electron 框架开发,推流等核心功能则依赖 OBS Node(obs-studio-node)实现,前端部分采用 Vue.js 技术栈。 OBS Studio 是一款知名的开源直播与录屏工具,其客户端使用 Qt 框架绘制界面。OBS Node 是将 OBS Studio 的核心功能模块进行封装,使其能够被 Node.js 直接调用的扩展库。 OBS 原生支持多种推流协议,但腾讯视频直播中台采用的是 TRTC(Tencent Real-Time Communication)协议。在此基础上,视频 PC 开播助手对 OBS Node 进行了以下扩展: TRTC 协议支持:实现基于 TRTC 的推流和连麦功能; 移动设备开播支持:支持使用手机等移动设备作为视频源进行开播。 整体技术架构如下图所示: 图 1|整体技术架构 Renderer 进程Vue UI ⇄ IPC ⇄ Main 进程Node + Native → OBS Node + TRTC SDK 腾讯体育后台服务(账号/房间/陪看控制) → Main 进程 虚拟主播(比赛点播转直播) → TRTC SDK 主播推流 → TRTC 云端混流 → 观众端 多房间架构设计(SubRoom) 陪看场景最大的技术约束是:主播需要同时处于主直播间和虚拟陪看房间。为此我们在 TRTC 单房间模型之上封装了 ITRTCSubRoom,并通过 SubRoomService 统一管理子房间生命周期。 ...

June 1, 2026

3D球场项目 (六):客户端工程化与优化

3D球场项目 (五) 把客户端的核心业务流 讲完了:Native 推送 → DataManager 队列 → ScenePlayer 章节调度 → GameController 状态机 → Handler → 渲染层。功能闭环跑通之后,真正的硬仗是 “工程化"和"性能”——前者保证 项目能稳定上线(编译跑通、退出不崩、Swift 调用顺手),后者保证在中低端机上画面流畅。 第一版上线时遇到了两类问题: 稳定性 / 工程化:modulemap 编译报错、lipo 架构冲突、A11 设备启动 crash、 Cocos 退出期 OpenAL 资源竞争 crash……这些都不是"画面卡",但每一个都能让用户体验 归零; 性能:中端 iPhone 在比赛回合渲染期间,GPU 和 CPU 都偶尔抖到 80%+,帧率掉到 30 fps 出头。 本篇按这两类拆成两部分,所有改动都遵循一条原则:不动玩法,只把工程问题和帧时间 解决掉。 架构改动一览 3D球场项目 (二) 介绍过弹幕引擎的四层 架构(腾讯视频 APP / MagicDanmakuiOS / MagicDanmaku / cocos-engine)。这一阶段 每一层都动了——3D 球场不是单点改造,而是一次自上而下的纵贯。下面这张图是把 PartTwo 那张原始架构图重画一遍,改动的节点用蓝色、新增的节点用绿色, 没动的节点保持白色: 未改动 本次改动 本次新增 腾讯体育 APP(新接入方) ▲ 业务层 SwiftUI(腾讯体育侧,PartFive §四 / 全部新增) InMatchTop3DLiveView QS3DCourtSwiftUIView QS3DCourtEventBroker CourtContainerControlOverlay TennisMatchScoreBoard TennisGameEventBoardView QS3DCourtViewController MagicDanmakuViewController ▲ 弹幕业务接入层 MagicDanmakuiOS(PartFive §三 + PartSix 第一部分) 资源包 业务接入层 JS 注册绑定 动态化 playground CocosPlayer(场景代理回滚) modulemap + framework A11 / lipo 构建修复 ▲ 弹幕实现 MagicDanmaku(PartFive §二 + PartSix 第二部分) Assets 资源包 TypeScript 版弹幕组件(原有,未改) 样式 轨道 特效 通信 … ★ 新增:3D 网球球场(assets/tennis/) Model / DataManager ScenePlayer GameController States × 6 Handlers × 7 Player / QSArmature Ball / Bezier+Physics Camera Audience(VAT) Shader 球场边线 素材 图片 视频 音频 网球资产(减面 / 压缩 / 合材) 二进制库 engine framework(重新打包) external framework(A11 兼容重编) ▲ 引擎内核 cocos-engine(PartFive §一 + PartSix §二、§三) 2D 3D 物理 粒子 … loadScene(进度 / 传参 / 4 阶段代理) JsbBridgeWrapper(内存语义) AudioEngine(OpenAL atomic 守卫) OC 头文件(Swift 友好标注) 引擎内核扩展 cocos-engine/native/external webp freetype … 一句话归纳: ...

May 31, 2026

3D球场项目 (五)

3D球场项目 (四) 把服务端推到了线上: 导演 Agent 把每个 Point 切成 SERVE / RALLY / CONCLUSION 三段,配齐了动作、机位、 位置、比分、解说,按 seq 单调下发到客户端。本篇回到客户端,看 Cocos 这一侧拿到 Script 之后,是怎么把它变成屏幕上一拍接一拍的比赛画面的。 整个客户端改造分四层落地,本篇只讲和 3D 球场主干业务直接相关的内容: CocosEngine 层:场景加载架构升级(进度 / 传参 / Delegate1 回调 / JSBridge2 内存语义); MagicDanmaku 层:3D 球场的核心业务代码(数据流、状态机、动画 / 球轨迹 / 相机 / 观众); MagicDanmaku iOS 层:场景加载回调的演化,以及 CocosPlayer 在调用链里的角色; 业务层:腾讯体育 App 的 SwiftUI3 视图把上面三层包成一个标准组件。 每一层和业务流程脱钩的内容(性能优化、稳定性 / crash 修复、构建工程化)统一抽到了 3D球场项目 (六):客户端工程化与优化。 下面这张图先把四层的位置关系和数据流向摆出来,读者可以把它当作整篇文章的导航—— 箭头是数据流方向(服务端 Script 自顶向下灌进引擎、引擎事件自底向上回到 SwiftUI), 每个节点旁标了对应章节: 数据入口 事件回流 服务端 Script(PartFour) 业务层 SwiftUI(腾讯体育 App) §四 — 把 Cocos View 包成 SwiftUI 组件,事件用 Combine Broker 双向桥接 InMatchTop3DLiveView QS3DCourtSwiftUIView QS3DCourtEventBroker CourtContainerControlOverlay TennisMatchScoreBoard TennisGameEventBoardView QS3DCourtViewController MagicDanmaku iOS 层(CocoaPods framework,对外导出) §三 — 把引擎符号 + CocosPlayer 一起导给业务层;场景就绪回调由消费者各自实现 CocosView CocosCreator JsbBridgeWrapper CocosPlayer CocosMessageInvoker CocosEngine 层(cocos-engine 内部分支) §一 — loadScene 全流程能力升级(进度 / 传参 / 4 阶段代理)+ JsbBridgeWrapper 内存修复 Director.loadScene CocosLoadSceneConfig.params CocosViewSceneDelegate(4 阶段协议) SceneManager.load MagicDanmaku 层:3D 球场业务(assets/tennis/...) §二 — 数据 → 状态机 → Handler → 渲染的单向漏斗 Model 层(§2.1) DataManager ScenePlayer RoundData Game 层(§2.2 / §2.3) GameController States × 6 Handlers × 7 ▼ QSPlayerController + QSArmature QSBallTraceController(Bezier / Physics) CameraController AudienceGenerator 橙色节点是 数据入口——Script JSON 从服务端推下来,最终落到 DataManager.receiveRawData()。紫色节点是 事件回流——比如场景加载成功 / 失败、 onRoundStart / onFirstFrameRendered 等事件,由底层逐层冒泡回 SwiftUI 视图。 ...

May 30, 2026

3D球场项目 (四)

项目终于来到了落地环节。 在3D球场项目 (三)里,我们用一段离线 PBP 数据 + 一次 LLM 调用,把"导演 Agent"的雏形跑了起来。Demo 阶段的脚本是离线生成、整段 导入的;那时的 LLM 既负责"想象画面",又顺手把动作、镜头、音效、解说词都打包了。 但项目一旦从 Demo 推到线上,导演 Agent 立刻面对三件事: Opta 数据是按 Point 持续推过来的,不会一次性把一场比赛喂给大模型; 大模型 会失败、会延迟,一旦卡住,球员就只能停在 idle; 客户端会断流、会重连,需要一个"刚才那一拍发生了什么"的回放接口。 上一章末尾提到的三个坑——player 卡 idle、两人一直来回发球、长链断了客户端不知道 怎么补——本质都来自这三件事。线上版本的 livecast 服务(基于 tRPC-Go)做了一次完整的 工程化:导演 Agent 不再是单一 LLM,而是 确定性脚本层 + LLM 解说层 + 双重下发保险 的组合。本篇就讲这套组合怎么搭起来。 一、网球数据是怎么进来的 NBA 那边的 PBP 是 单条 投递:上游每发生一个篮球事件,就经 Kafka 推一条消息过来。 但网球数据天然是 按回合聚合 的——Opta 在一个 Point(一个回合)结束之后才会一次性 把这一拍涉及的所有事件下发,所以服务端也用了批量消费通道: Kafka topic: pbp_flow └─ FlowConsumer.BatchHandle(msgs []*sarama.ConsumerMessage) └─ livecastSvc.ProcessBatchPBPFlow(payloads [][]byte) 进入 ProcessBatchPBPFlow 之后,先按 mid(match id)做二级分组、过滤掉非网球的批次, 再交给真正的 pipeline。两道闸门决定一场比赛的事件能不能走 3D 流水线: ...

May 30, 2026

3D球场项目 (三)

在3D球场项目 (二)中,我们梳理了视频弹幕引擎的整体架构、引擎初始化流程。现在,3D 球场部分基本已经探索完毕,我们接下来就是要解决这个项目的数据驱动部分了。 我们现在研究一下下发数据的来源:Opta,它是全球顶级的体育数据公司,1996 年创立于英国伦敦,现隶属于 Stats Perform,是行业公认的足球数据金标准。 覆盖:20+ 运动、3900+ 赛事、每年 6 万 + 场比赛 规模:7.2PB 历史数据、年采集超 10 亿数据点 精度:单场足球2 万 + 事件点,事件识别准确率 99.8% 腾讯体育采买了 Opta WTA 网球比赛的数据,我们可以通过 Opta 的 API 来获取数据。 根据他们官网的介绍,一个 MA3 网球赛事数据中 typeId 对应的意义如下: 点击展开 / 折叠 Event TypeId 完整对照表 Event TypeId Event Name Description 20 STOP_GAME Indicates that the game has finished. 41 START_SET_1 Start 1st Set 42 START_SET_2 Start 2nd Set 43 START_SET_3 Start 3rd Set 44 START_SET_4 Start 4th Set 45 START_SET_5 Start 5th Set 46 STOP_SET Stop Set 47 T_WO1 w.o. Player 1 48 T_WO2 w.o. Player 2 128 SAFE Safe (No longer used) 129 DANGER Danger (Technical/connection issue at venue) 132 INJ_BREAK Game suspended - Player injured 133 PLAYERS_COMING_OUT Players coming out 141 GAME_ABOUT_TO_START Game about to start 149 GAME_SUSPENDED Game suspended 160 PLAYERS_WARMING_UP Players warming up 162 SHAKE_HANDS_WITH_REFEREE Players shake hands with referee 163 COIN_FLIPPING_FOR_FIRST_SERVER Coin flip to choose first server 164 PLAYERS_TALKING_TO_REFEREE Player(s) talking to the referee 165 REFEREE_CHECKING_POINTMARK Referee checking pointmark 166 BOTH_PLAYERS_SEATED Both players seated 167 PLAYER1_RECEIVING_TREATMENT Player 1 receiving treatment 168 PLAYER2_RECEIVING_TREATMENT Player 2 receiving treatment 169 PLAYERS_GOING_TO_COURT Players going back to court 170 NEXT_GAME_ABOUT_TO_START Next game is about to start 180 T_MORE_THAN_5 Rally, over five shots 181 T_MORE_THAN_10 Rally over ten shots 182 T_MORE_THAN_15 Rally over fifteen shots 187 T_POINT_UNDER_INVESTIGATION Point under investigation 188 T_START_TIE_BREAK Start tie break 191 T_POINT_STOPPED_BY_REF Point stopped by referee 197 UPDATE_SCORE_START Start score update 198 UPDATE_SCORE_FINISHED Score update finished 200 SIDE_CHANGE Side change 206 SHOT_CNT Shot count 216 STATISTIC_VERIFICATION Statistics confirmation 240 NEW_BALLS New balls 241 UMPIRE_ON_COURT UMPIRE ON COURT 242 WARMING_UP_VOLLEY Warming up - volley 243 WARMING_UP_SERVICE Warming up - service 244 ONE_MINUTE One minute 245 TIME Time 246 SHOT_DETAILS Shot details 256 CLS Cancel last sent event 257 CLR Clear events 258 GCC Game conditions changed. 261 SCORER Event details for %RELATED_EVENT% in the %MIN%. minute changed 262 BP Ball position event 264 ODD Odds event (deprecated) 266 TIME_CORRECTION_EVENT Correct timestamp for a missed event 276 START_GAME_CLOCK The (stopped) game clock is (re)started the game is running 277 STOP_GAME_CLOCK The game clock is stopped. Time will not change until Start Game Clock is sent again 278 ADJUST_GAME_CLOCK Game clock value is adjusted manually 279 CSTAT A statistical value is cleared and an additional event with the correct action is sent (e.g. an invalid Ace Home event is replaced by a Service Winner Home) 280 CONF_PERIOD_SCORE Period score confirmed 282 TIME_ADAPTION Time for event %RELATED_EVENT% was adapted by %SEC% seconds 285 PLAYER_DATA_CONFIRMED Player data for %RELATED_EVENT% in the %MIN% confirmed 513 SYS_MSG System Message 514 SCOUT_IN_STADION Scout in Stadium 515 CONNECTION_PROBLEMSSCOUT_OFFLINE Connection problems Scout offline 516 CONNECTION_PROBLEMS Connection problems 517 TRANSMISSION_ONLINE Transmission online 520 LINEUP_CHANGED Line-up changed 524 JERSEY_CHANGED Jersey colors updated 782 GAME CANCELLED Automatic “Game cancelled” event after first “cancellation” System message is sent 1152 T_SERVE1 Service Player 1 1153 T_1ST_SERVICE1 1st service Player 1 1154 T_2ND_SERVICE1 2nd service Player 1 1155 T_NA1 Net approach player 1 1156 T_W_FH1 Winner (forehand) Player 1 1157 T_W_BH1 Winner (backhand) Player 1 1158 T_FE_FH1 Forced error (forehand) Player 1 1159 T_FE_BH1 Forced error (backhand) Player 1 1160 T_UE_FH1 Unforced error (forehand) Player 1 1161 T_UE_BH1 Unforced error (backhand) Player 1 1162 T_HE1 Hawkeye Player 1 1163 T_WBR1 Warning by referee Player 1 1164 T_CBR1 Cautioned by referee Player 1 1165 T_SRV_NET1 Net Player 1 1166 T_SRV_OUT1 Out Player 1 1167 T_SRV_FF1 Foot fault Player 1 1168 T_SRV_DF1 Double fault Player 1 1169 T_SRV_A1 Ace Player 1 1170 T_SRV_SW1 Service winner Player 1 1171 T_SRV_RW_FH1 Return winner (forehand) Player 1 1172 T_SRV_IN1 Serve in Player 1 1173 T_POINT1 Point Player 1 1174 T_CONF1 Confirm Point Player 1 1175 T_GAME1 Game Player 1 1176 T_SET1 Set Player 1 1177 T_BL1 Baseline Player 1 1178 T_SRV_NR1 Net/Retake Player 1 1179 T_W1 Winner Player 1 1180 T_FE1 Forced error Player 1 1181 T_UE1 Unforced error Player 1 1182 T_SRV_RW_BH1 Return winner (backhand) Player 1 1183 T_V_FH1 Volley (forehand) Player 1 1184 T_V_BH1 Volley (backhand) Player 1 1185 T_BB1 Break ball Player 1 1186 T_B1 Break Player 1 1187 T_HES1 Hawk eye successful Player 1 1188 T_ITO1 Injury Timeout Player 1 1189 T_START_SRV1 Start Service Player 1 1190 T_WARNING1 1st offence - warning Player 1 1191 T_PENALTY_POINT1 2nd offence - penalty point Player 1 1192 T_PENALTY_GAME1 3rd offence - penalty game Player 1 1193 T_DISQUALIFICATION1 Disqualification Player 1 1194 T_UE_NET1 Unforced error net Player 1 1195 T_FE_NET1 Forced error net Player 1 1196 T_SUCCESSFUL_NET_APPROACH1 Successful net approach Player 1 1197 T_TIME_VIOLATION1 Time violation Player 1 1198 T_PENALTY_POINT1 T_UNSUCCESSFUL_NET_APPROACH1 Unsuccessful net approach Player 1 1199 T_AT_NET1 At net Player 1 1200 T_AT_BASELINE1 At baseline Player 1 1201 T_SET_BALL1 Set ball Player 1 1202 T_MATCH_BALL1 Match ball Player 1 2176 T_SERVE2 Service Player 2 2177 T_1ST_SERVICE2 1st service Player 2 2178 T_2ND_SERVICE2 2nd service Player 2 2179 T_NA2 Net approach player 2 2180 T_W_FH2 Winner (forehand) Player 2 2181 T_W_BH2 Winner (backhand) Player 2 2182 T_FE_FH2 Forced error (forehand) Player 2 2183 T_FE_BH2 Forced error (backhand) Player 2 2184 T_UE_FH2 Unforced error (forehand) Player 2 2185 T_UE_BH2 Unforced error (backhand) Player 2 2186 T_HE2 Hawkeye Player 2 2187 T_WBR2 Warning by referee Player 2 2188 T_CBR2 Cautioned by referee Player 2 2189 T_SRV_NET2 Net Player 2 2190 T_SRV_OUT2 Out Player 2 2191 T_SRV_FF2 Foot fault Player 2 2192 T_SRV_DF2 Double fault Player 2 2193 T_SRV_A2 Ace Player 2 2194 T_SRV_SW2 Service winner Player 2 2195 T_SRV_RW_FH2 Return winner (forehand) Player 2 2196 T_SRV_IN2 Serve in Player 2 2197 T_POINT2 Point Player 2 2198 T_CONF2 Confirm Point Player 2 2199 T_GAME2 Game Player 2 2200 T_SET2 Set Player 2 2201 T_BL2 Baseline Player 2 2202 T_SRV_NR2 Net/Retake Player 2 2203 T_W2 Winner Player 2 2204 T_FE2 Forced error Player 2 2205 T_UE2 Unforced error Player 2 2206 T_SRV_RW_BH2 Return winner (backhand) Player 2 2207 T_V_FH2 Volley (forehand) Player 2 2208 T_V_BH2 Volley (backhand) Player 2 2209 T_BB2 Break ball Player 2 2210 T_B2 Break Player 2 2211 T_HES2 Hawk eye successful Player 2 2212 T_ITO Injury Timeout Player 2 2213 T_START_SRV2 Start Service Player 2 2214 T_WARNING2 1st offence - warning Player 2 2215 T_PENALTY_POINT2 2nd offence - penalty point Player 2 2216 T_PENALTY_GAME2 3rd offence - penalty game Player 2 2217 T_DISQUALIFICATION2 Disqualification Player 2 2218 T_UE_NET2 Unforced error net Player 2 2219 T_FE_NET2 Forced error net Player 2 2220 T_SUCCESSFUL_NET_APPROACH2 Successful net approach Player 2 2221 T_TIME_VIOLATION2 Time violation Player 2 2222 T_AT_NET2 Unsuccessful net approach Player 2 2223 At net Player 2 2224 T_AT_BASELINE2 At baseline Player 2 2225 T_SET_BALL2 Set ball Player 2 2226 T_MATCH_BALL2 Match ball Player 2 PBP = Play-by-Play(逐回合 / 逐事件数据),就是把一场比赛里每一次事件都按时间线秒级记录下来的最细粒度原始数据流。口语里也叫 “逐帧数据 / 流水账数据”。网球赛事的数据,都是以这个形式下发的,一段数据可能下发的数据是这样的: ...

May 30, 2026

3D球场项目 (二)

在3D球场项目 (一)中,我们搞定了 3D 资产,也选定了落地框架。但是这不代表我们可以直接使用,这个作为的弹幕引擎的一部引入的 Cocos,是有一些定制逻辑在的。我们需要抽丝剥茧的先了解这个弹幕系统做了什么,再来制定具体的实施方案。 视频弹幕引擎 腾讯视频的弹幕引擎作为一个悠久的项目,支撑了腾讯视频大量的互动活动。弹幕引擎框架也是几经迭代,从最早的原生版本,到 PAG,再到现在的 Cocos Creator版本。 之所以想要使用 Cocos 来替换原来的方案,是因为有以下两大优势: 能力强: 支持完善的图形渲染、运动、物理、粒子、3D、光照等游戏引擎能力,充分利用游戏引擎所提供的这些能力,可以在弹幕上实现丰富的玩法。 跨平台: Cocos Creator 是一款高效、清凉、免费开源的跨平台图形引擎,支持所有主流平台支持,真正实现一次开发,全平台运行。框架迭代几乎都是使用 Cocos Creator 开发,少部分业务,如数据上报、客户端交互等,才需要做做少量适配工作,这极大的节省了人力; 动态化: 动态发布新特性和配置能力,更方便配合运营做活动,不需要等 app 发版铺量; 弹幕引擎的工程划分,大致如下: 腾讯视频 APP ▲ 弹幕业务接入层 MagicDanmakuiOS 资源包 业务接入层 JS 注册绑定 动态化 playground … ▲ 弹幕实现 MagicDanmaku Assets 资源包 TypeScript 版弹幕组件 样式 轨道 特效 通信 … 素材 图片 视频 音频 … 二进制库 engine framework external framework ▲ 引擎内核 cocos-engine 2D 3D 物理 粒子 … 引擎内核扩展 cocos-engine/native/external webp freetype … 从上面的结构图来看,弹幕整体架构划分了 3 层: 引擎内核层: 是 Cocos Creator 引擎内核仓库,内部依赖了第三方库仓库,其中 Cocos Engine 是官方 3.8.3 版本的 fork版本,进行了一些定制化修改(比如单 Metal View复用)等等; external framework 同样也是官方版本的 fork版本,包括但不限于 webp、SSL、Freetype 等; 跨端弹幕层 MagicDanmaku 是一份 Cocos Creator工程,用于存在业务 TS 代码、Assets 资源,弹幕和我们后续的 3D 球场的业务逻辑,都存放在这里; 业务接入层 MagicDanmakuiOS 是将上面 MagicDanmaku 打包后的产物接入到 iOS 工程的组件,用于输入业务数据、桥接/注册 JS 层逻辑、动态化能力实现; MagicDanmaku 工程探索 我们起初新建一个 Cocos 项目来进行开发,计划是仅拿出打包工程的 JS 及 assets 部分拿到主工程,复用已有逻辑来进行加载。 ...

May 30, 2026

小红书-社招-5年 · 第 2 轮 · 技术面试

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 本轮概述: 该轮面试主要考察了浏览器的工作原理、缓存策略、跨域、Vue生命周期、组件通信等方面的知识。题目涉及理论知识和实际应用场景。 本轮共 14 道题。答案默认折叠,便于先自行作答。 1. 详细讲一下从url输入网址到页面渲染的过程 题库原题:简单描述从输入网址到页面显示的过程 题目要点 当输入URL到页面加载完成,发生了以下几个关键过程: DNS解析:浏览器将URL解析为对应的IP地址。这个过程涉及多级DNS服务器,从本地缓存开始,如果没有找到,则递归查询根域名服务器、顶级域名服务器,直到找到目标服务器的IP地址。 TCP连接:浏览器通过三次握手与服务器建立TCP连接。一旦连接建立,浏览器可以发送HTTP请求。 HTTP请求:浏览器构建HTTP请求报文,通过TCP连接发送到服务器。请求报文包含请求行、请求头和请求正文。 服务器处理请求:服务器接收HTTP请求,解析请求内容,执行相应的处理(如数据库查询、文件读取等),并构建HTTP响应报文。 HTTP响应:服务器将响应报文通过TCP连接发送回浏览器。响应报文包含状态码、响应头和响应正文。 浏览器解析渲染:浏览器接收到HTTP响应后,解析HTML文档构建DOM树,解析CSS构建CSSOM树,合并两者形成渲染树,然后开始渲染页面。 连接结束:当浏览器完成页面渲染或收到服务器关闭连接的信号时,浏览器会发送TCP连接关闭的信号,服务器收到后,双方断开连接。 参考答案 很多大公司面试喜欢问这样一道面试题,输入URL到看见页面发生了什么? 简单来说,共有以下几个过程: DNS解析 发起TCP连接 发送HTTP请求 服务器处理请求并返回HTTP报文 浏览器解析渲染页面 连接结束 下面我们来看看具体的细节。 DNS解析 DNS解析实际上就是寻找你所需要的资源的过程。假设你输入www.baidu.com,而这个网址并不是百度的真实地址,互联网中每一台机器都有唯一标识的IP地址,这个才是关键,但是它不好记,乱七八糟一串数字谁记得住啊,所以就需要一个网址和IP地址的转换,也就是DNS解析。 DNS解析其实是一个递归的过程。 输入www.google.com网址后,首先在本地的域名服务器中查找,没找到去根域名服务器查找,没有再去com顶级域名服务器查找,,如此的类推下去,直到找到IP地址,然后把它记录在本地,供下次使用。大致过程就是.-> .com ->google.com. -> www.google.com.。 (最后这个.对应的就是根域名服务器,默认情况下所有的网址的最后一位都是.,为了方便用户,通常都会省略,浏览器在请求DNS的时候会自动加上) DNS优化 既然已经懂得了解析的具体过程,我们可以看到上述一共经过了N个过程,每个过程有一定的消耗和时间的等待,因此我们得想办法解决一下这个问题! DNS缓存 DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,ISP服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。 DNS负载均衡 比如访问baidu.com的时候,每次响应的并非是同一个服务器(IP地址不同),一般大公司都有成百上千台服务器来支撑访问。DNS可以返回一个合适的机器的IP给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡。 发起TCP连接 TCP提供一种可靠的传输,这个过程涉及到三次握手,四次挥手。 三次握手 第一次握手: 客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手: 服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(Seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手: 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。 四次挥手 数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,假设客户端主动关闭,服务器被动关闭。 第一次挥手: 客户端发送一个FIN,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,客户端依然会重发这些数据),但是,此时客户端还可以接受数据。 FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。 第二次挥手: 服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号seq,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。 ...

February 1, 2026

小红书-社招-5年 · 第 1 轮 · 技术面试

← 已是第一轮 · 返回本次面经 · 第 2 轮 → 本轮概述: 该轮面试主要考察了前端基础知识,包括BFC、浮动元素、作用域、异步编程、Webpack、Vue等多方面的内容。题目涉及理论知识和代码实现。 本轮共 18 道题。答案默认折叠,便于先自行作答。 1. BFC讲一下 题库原题:什么是BFC? 题目要点 BFC(Block Formatting Context) 是 CSS 中一个重要的布局概念,它描述了一个块级元素的内部布局和外部布局之间的关系。BFC 主要用于处理元素的布局、浮动、边距合并等问题。 BFC 的作用 阻止外边距折叠: 外边距折叠:当两个块级元素垂直相邻时,它们的外边距会合并,形成一个更大的外边距。 BFC:在 BFC 内部的元素的外边距不会影响到外部 BFC 的元素,避免了外边距折叠的问题。 包含浮动元素: 浮动元素:通常会从其包含块中溢出。 BFC:具有 BFC 的元素可以包含其内部的浮动元素,确保其高度包括浮动元素的高度。 控制元素的布局: BFC:在 BFC 内部,元素的布局(如浮动、定位)会受到影响和控制,避免与外部元素发生冲突。 防止元素重叠: BFC:能够隔离不同的 BFC 区域,避免元素之间的重叠或干扰。 如何触发 BFC BFC 会在以下情况中被触发: 块级格式化上下文的创建: 元素的 display 属性值为 block 或 inline-block。 元素的 position 属性值为 absolute 或 fixed。 元素的 float 属性值为 left 或 right。 元素的 overflow 属性值为 hidden、scroll 或 auto。 其他常见触发情况: ...

February 1, 2026

小红书-社招-3年 · 第 3 轮 · 技术面试

← 第 2 轮 · 返回本次面经 · 已是最后一轮 → 本轮概述: 这一轮主要考察了小程序的低代码设计架构、Web Worker的使用、中台系统的微前端拆分策略等方面的知识。 本轮共 4 道题。答案默认折叠,便于先自行作答。 1. 讲一下你关于小程序的低代码设计架构 题目要点 小程序低代码架构本质是配置驱动的运行时体系,核心包括 DSL 协议设计、组件注册机制、运行时解析与数据驱动更新;必须围绕 setData 性能约束进行差量更新与渲染优化;工程重点不在编辑器,而在运行时引擎的性能治理与扩展能力设计。 参考答案 小程序的低代码架构,本质是在受限运行环境下实现“可配置驱动 UI 与逻辑”。核心不是拖拽能力,而是如何让页面结构、交互逻辑、数据流都由配置驱动,同时保证性能与可维护性。 一、整体架构分层 小程序低代码一般分为四层: 编辑层 → DSL 层 → 运行时引擎 → 渲染层 编辑层负责产出结构化配置;DSL 层定义组件树与属性协议;运行时负责解析与调度;渲染层落在小程序原生组件体系之上(如 WXML + setData 机制,在 微信小程序 中即运行于其渲染框架内)。 关键问题在于:小程序不是虚拟 DOM 模型,而是逻辑层与视图层分离,通过 JSON 数据桥接,因此架构必须围绕数据驱动。 二、DSL 设计 DSL 通常采用 JSON Schema 形式,核心包含: 组件类型 属性 props 样式 事件绑定 数据源 条件显示规则 低代码的关键在于“协议稳定性”,一旦 DSL 设计混乱,后续扩展成本会极高。因此会设计: 组件注册机制 属性校验规则 默认值策略 版本兼容策略 三、运行时引擎 运行时是核心。 ...

February 1, 2026

小红书-社招-3年 · 第 2 轮 · 技术面试

← 第 1 轮 · 返回本次面经 · 第 3 轮 → 本轮概述: 这一轮主要考察了小程序的性能优化、核心监控指标、首屏时间的计算、业务价值验证、高频事件处理等方面的知识。 本轮共 11 道题。答案默认折叠,便于先自行作答。 1. 小程序性能优化做了哪些事情? 题库原题:小程序可以做哪些性能优化? 题目要点 小程序性能优化围绕逻辑层与视图层分离架构展开,重点是减少 setData 频率与数据体积,控制列表节点数量,优化首包体积与启动链路,并通过分包加载、WXS 与懒加载等手段降低渲染压力。核心原则是减少跨线程通信与避免无意义重渲染,从架构层面解决性能瓶颈。 参考答案 小程序的性能优化,不能只从“前端渲染”角度看。它的运行模型和 Web 不同,存在 逻辑层(JSCore)与视图层(WebView)分离 的架构特征,核心瓶颈往往出在: 跨线程通信成本 setData 传输体积 渲染节点数量 包体与启动链路 优化必须围绕这些机制展开。 一、理解运行架构是前提 以 微信小程序 为例: 逻辑层:JS 执行环境 视图层:WebView 渲染 两层通过 JSON 序列化通信 每一次 setData: 数据序列化 线程间传输 视图层 diff 真实节点更新 所以小程序性能优化的第一原则是: 减少跨线程通信的数据量与次数。 二、控制 setData 的粒度与频率 1. 避免大对象全量更新 错误方式: this.setData({ form: newFormObject }) 如果 form 很大,每次都会整体传输。 正确方式: this.setData({ "form.username": value }) 使用路径更新,最小化数据传输。 2. 合并多次 setData 多次调用: ...

February 1, 2026