面灵AI→

京东前端实习 AI 面:TS 校验、JWT 安全与流式渲染

轮次
AI 面
时间
2026-10
来源
牛客网

《面试题目》

  1. 自我介绍和项目介绍。
  2. 在项目的开发和实际运行中,使用 TS 相比于 JS 有哪些优势?
  3. 项目中如何使用 TS + Zod 进行接口和数据的校验和运行兜底,有哪些实际案例?
  4. 具体讲讲刚才在校验中提到的 Unicode 的作用、优势和实际运用在了哪里?
  5. 在开发中使用 React 框架相比于使用纯原生 JS 的区别和具体优势?
  6. 使用 Vite 相比于 webpack 的开发模式来说,在冷启动、热更新上有哪些实际的优化体验?
  7. 结合项目实际开发讲讲,如果把 JWT 放到 localStorage 中相比于放到 cookie 中,具体会有哪些 XSS 可能带来的风险?
  8. XSS 面对 JWT 具体的攻击是怎样的?在项目中具体是如何防范 CSRF 攻击的?
  9. 如果让你设计一个白名单进行 CSRF 的过滤方案,你具体会怎么做?
  10. 项目中 AI 审核流式数据展示,前端接收这些数据时对于大量的数据,为优化 UI 交互流畅性,你会如何设计?
  11. 项目中为什么选择通过 function calling 来进行接口调用和数据校验?
  12. 你说了这么多安全校验的设计,在实际项目上线中拦截了多少异常越权与不规范的接口访问?
  13. 假设你设计的后端界面变动太大,被后端同学以接口难对齐为由拒绝,你会如何处理?

《参考解析》

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 用数据说话(改动成本、影响面)。关键是展示你会把讨论从「谁对谁错」转成「哪种方案代价更小」。