京东前端实习 AI 面:TS 校验、JWT 安全与流式渲染
- 轮次
- AI 面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍和项目介绍。
- 在项目的开发和实际运行中,使用 TS 相比于 JS 有哪些优势?
- 项目中如何使用 TS + Zod 进行接口和数据的校验和运行兜底,有哪些实际案例?
- 具体讲讲刚才在校验中提到的 Unicode 的作用、优势和实际运用在了哪里?
- 在开发中使用 React 框架相比于使用纯原生 JS 的区别和具体优势?
- 使用 Vite 相比于 webpack 的开发模式来说,在冷启动、热更新上有哪些实际的优化体验?
- 结合项目实际开发讲讲,如果把 JWT 放到 localStorage 中相比于放到 cookie 中,具体会有哪些 XSS 可能带来的风险?
- XSS 面对 JWT 具体的攻击是怎样的?在项目中具体是如何防范 CSRF 攻击的?
- 如果让你设计一个白名单进行 CSRF 的过滤方案,你具体会怎么做?
- 项目中 AI 审核流式数据展示,前端接收这些数据时对于大量的数据,为优化 UI 交互流畅性,你会如何设计?
- 项目中为什么选择通过 function calling 来进行接口调用和数据校验?
- 你说了这么多安全校验的设计,在实际项目上线中拦截了多少异常越权与不规范的接口访问?
- 假设你设计的后端界面变动太大,被后端同学以接口难对齐为由拒绝,你会如何处理?
《参考解析》
TS 相比 JS 的实际收益:要讲「在真实项目里省了什么」,而不是类型系统的定义。三点最实:一是重构安全——改接口字段时编译期就能把调用点全找出来,这是纯 JS 做不到的;二是接口契约前置——前后端约定先落到类型上,减少联调期的「字段名不一致」;三是可读性/自文档化——联合类型和字面量类型本身就是文档。也要承认代价:类型体操会增加维护成本,any 滥用会让收益归零。
TS + Zod 的分工:TS 只在编译期,运行时拿到的 JSON 是不可信的,所以需要 Zod 在边界(接口响应、表单、本地存储、URL 参数)做运行时校验。典型写法是「Zod schema 为单一来源,类型从 schema 推导(z.infer)」,避免类型和校验两处维护。实际案例:接口返回的字段可能为 null、可能是字符串数字,用 safeParse 兜住并在失败时降级到默认值或提示,而不是让错误传播到渲染层炸掉页面。
Unicode 在校验中的用途:常见于两类场景。一是输入规范化——同一个字符有多种码点表示(NFC/NFD),用户名、文件名、搜索关键词要先 normalize 再比较和入库,否则「看起来一样」的两个名字会被当成不同值绕过唯一性;二是字符范围校验——用码点范围限制表情、零宽字符、双向控制符(同形异义攻击),防止伪装成正常文本的恶意内容。也用于长度计算:'👨👩👧'.length 和用户感知的长度不是一回事,用 Intl.Segmenter 或码点计数才准。
React 与原生 JS:核心差别是声明式 + 状态驱动。原生要自己维护 DOM 与数据的同步,一处状态改了要记得改所有相关节点;React 用状态描述 UI,diff 交给框架。附带的收益是组件化复用、生态(路由、状态管理、表单)、以及并发特性(Suspense、transition)带来的交互体验。代价是包体积、抽象泄漏(重渲染、依赖数组)需要理解。
Vite 与 webpack 的开发体验:webpack 启动要先打包整个依赖图,冷启动随项目规模线性增长;Vite 开发态用原生 ESM,按需编译,启动基本是常量级。HMR 上 Vite 只让改动模块及其边界失效,webpack 在做完依赖分析后也快了,但边界传播范围通常更大。生产构建 Vite 走 Rollup(或 Rolldown),webpack 的持久缓存和生态更成熟。
JWT 放 localStorage 的 XSS 风险:localStorage 能被任意同源 JS 读到,一旦有一处 XSS(哪怕是第三方脚本、富文本渲染、依赖投毒),token 就被直接偷走,而且没有 httpOnly 保护。放 httpOnly cookie 则 JS 读不到,但会引入 CSRF 面。所以正确答案不是「放哪」,而是组合:token 放 httpOnly + Secure + SameSite 的 cookie,配合 CSRF token(双提交或同源校验);如果必须放 localStorage,就要把 XSS 面压到最小(CSP、避免 innerHTML、依赖审计)并缩短 token 有效期 + 刷新令牌轮换。
CSRF 白名单方案:思路是「默认拒绝,显式放行」。落地包含:只对安全方法(GET/HEAD/OPTIONS)放行,写操作必须带 token;校验 Origin/Referer 是否在白名单内;双提交 cookie(csrf token 放 cookie 同时放进请求头,服务端比对);白名单本身按环境区分、支持路径级配置,并且不能只靠 Referer(可能被裁掉或被伪造场景绕过)。
流式数据的渲染优化:核心是「别让每个 token 都触发一次全量渲染」。做法:按帧或按时间窗批量合并(比如 30~60ms 更新一次),用 ref 累积文本、只在批量点 setState;长文本用虚拟滚动或分段渲染,避免整块 DOM 反复重排;把 Markdown 解析放在 worker 或做成增量解析,避免主线程卡顿;滚动跟随要节流,并允许用户上滑后脱离自动跟随。
function calling 的选型理由:相比「让模型输出自由文本再正则解析」,function calling 输出的是结构化参数,schema 由服务端定义、模型受约束,解析失败率低;同时它天然把「决定做什么」和「怎么做」分开——模型只给意图和参数,真正的调用由后端执行并校验权限,安全边界更清晰。
「拦截了多少攻击」这类问题怎么答:个人项目确实没有真实攻击量,硬编数字会崩。老实说「这是个人项目,没有生产流量,我验证的方式是构造用例做渗透测试(列出具体用例)」,然后转到达成效果上:加了哪些校验、用什么工具测的、发现了什么漏洞并修掉。这比一个假数字可信得多。
前后端接口冲突怎么处理:先分清是「设计不合理」还是「沟通成本」。做法:把争议落到契约上(OpenAPI/类型定义),用 mock 先并行开发;把破坏性变更做成版本化或在网关做适配层;真有分歧就拉上双方 leader 用数据说话(改动成本、影响面)。关键是展示你会把讨论从「谁对谁错」转成「哪种方案代价更小」。