面试题手册

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

服务端阅读 05月29日 23:47

如何优化 Babel 编译性能?哪些配置最有效?

优化 Babel 编译性能,优先做三件事:少编译、用缓存、少插件。少编译就是用 include 精准限定源码目录,不要把整个 node_modules 丢给 Babel;用缓存就是开启 babel-loader 的 cacheDirectory 和配置层的 api.cache(true);少插件就是只保留必要转换,能交给 esbuild/SWC 的纯语法转换就别强行走 Babel。再往下才是 targets、polyfill 和并行。@babel/preset-env 的 targets 越准确,Babel 做的无用转换越少;useBuiltIns: 'usage' 可以减少 polyfill 体积;大型 Webpack 项目可配合 thread-loader,但小项目并行成本可能比收益还高。追问为什么 include 往往比 exclude 更稳?exclude 容易漏掉特殊目录,include 是白名单,只编译明确需要处理的源码和少数第三方包,性能和可控性都更好。cacheDirectory 能解决什么问题?它会缓存 babel-loader 的转换结果,二次构建只处理变更文件。开发环境收益最大,常能把重复编译时间降很多。targets 配错会怎样?目标浏览器写得太旧,Babel 会做大量降级和 polyfill;写得太新,旧环境可能跑不起来。性能优化不能牺牲兼容性。什么时候用 SWC 或 esbuild 替代 Babel?如果只是 JSX、TS 或 ES 语法转换,SWC/esbuild 更快。如果依赖 Babel 插件生态,比如自定义 AST 插件,仍然要用 Babel。写段代码module.exports = api => { api.cache(true); return { presets: [['@babel/preset-env', { targets: '>0.5%, not dead', modules: false }]] };};
服务端阅读 05月29日 23:47

Babel 如何接入 Webpack、Vite 和 Rollup?

Babel 接入构建工具的核心思路是:让构建工具负责文件扫描、依赖图和打包,Babel 只负责把指定源码转换成目标语法。Webpack 通常用 babel-loader,Vite 默认走 esbuild,只有需要 Babel 插件时才通过 React 插件或 Babel 插件接入,Rollup 用 @rollup/plugin-babel,库开发还要特别处理 helpers。关键不是“能不能接”,而是“什么时候该接”。如果只是语法降级,Vite/esbuild 或 SWC 往往更快;如果要 decorators、宏、React 特定转换、自定义 AST 插件,才值得引入 Babel。追问Webpack 里 Babel 放在哪一层?放在 module rules 的 loader 阶段。Webpack 匹配 js/jsx/ts/tsx 文件后交给 babel-loader,Babel 根据 preset 和 plugin 输出新代码。Vite 为什么默认不依赖 Babel?因为 Vite 开发阶段追求速度,默认用 esbuild 做转译。只有遇到 Babel 生态里的插件能力,比如 legacy decorators,才需要补 Babel。Rollup 里 babelHelpers 怎么选?应用打包可用 bundled,helpers 直接打进产物。库开发更推荐 runtime,并把 @babel/runtime 设为 external,避免每个包重复注入 helpers。实际项目里容易踩什么坑?最常见是把整个 node_modules 都交给 Babel,构建变慢。更稳的做法是用 include 精准指定 src 和少数需要转译的第三方包。写段代码// webpack.config.jsmodule.exports = { module: { rules: [{ test: /\.[jt]sx?$/, include: /src/, use: { loader: 'babel-loader', options: { cacheDirectory: true } } }] }};
服务端阅读 05月29日 23:47

什么是 Babel AST?如何用它写自定义插件?

Babel AST 是源码解析后的抽象语法树,Babel 插件本质上就是“遍历这棵树,找到目标节点,再改掉它”。完整流程是:parser 把代码转成 AST,traverse 按 visitor 访问节点,插件通过 path.remove、replaceWith、insertBefore 等方法修改节点,最后 generator 再生成代码。写插件时不要直接乱改 node,优先用 path,因为 path 带着父节点、作用域、替换/删除能力。比如删掉 console.log,要访问 CallExpression,判断 callee 是否是 console.log,然后 remove。追问AST 和普通字符串替换有什么区别?字符串替换只看文本,容易误伤注释、变量名或字符串。AST 能理解语法结构,比如只删除真正的函数调用,不会碰到字符串里的 console.log。visitor 为什么按节点类型写?因为 Babel 遍历 AST 时会按节点类型触发回调。你关心函数调用就写 CallExpression,关心变量名就写 Identifier。path.scope 有什么用?它用于处理作用域绑定,比如判断变量是否在当前作用域声明、重命名变量、生成不冲突的临时变量。写复杂插件时这是避免变量污染的关键。项目里最容易踩什么坑?最常见的是替换节点后又被继续遍历,导致重复处理。可以在必要时用 path.skip(),或者给新节点加标记避免二次转换。写段代码module.exports = ({ types: t }) => ({ name: 'remove-console-log', visitor: { CallExpression(path) { const c = path.node.callee; if ( t.isMemberExpression(c) && t.isIdentifier(c.object, { name: 'console' }) && t.isIdentifier(c.property, { name: 'log' }) ) path.remove(); } }});
服务端阅读 05月29日 23:47

什么是 cURL?它在 Web 开发中有什么作用?

cURL 是一个命令行数据传输工具,也是一套库,常用来通过 URL 发起 HTTP/HTTPS 请求。Web 开发里它最常见的作用是调试 API:不用写页面、不用打开 Postman,直接在终端复现 GET、POST、请求头、Cookie、鉴权和上传下载问题。追问cURL 和 Postman 有什么区别?Postman 更适合可视化调试和团队管理接口;cURL 更轻、更容易复制到终端、脚本、CI/CD 或线上机器里排查问题。很多接口文档也会直接给 cURL 示例,因为它可执行、可复现。cURL 在项目里通常怎么用?前后端联调时,用它验证接口是否真的可访问;线上排障时,用它检查状态码、响应头、重定向和 TLS;自动化脚本里,用它做健康检查或触发 Webhook。它只支持 HTTP 吗?不是。cURL 支持 HTTP、HTTPS、FTP、SFTP、SMTP 等多种协议,只是 Web 开发中最常用的是 HTTP/HTTPS。面试里怎么回答更像真用过?可以说自己用 curl -i 看响应头,用 -H 带 token,用 -d 复现 POST 请求,用 -v 排查 DNS、TLS 或连接失败。这样比只背“命令行工具”更具体。写段代码# 查看接口是否可访问curl -i https://api.example.com/users# 带 Token 调 APIcurl -H "Authorization: Bearer token" \ https://api.example.com/profile# 提交 JSONcurl https://api.example.com/users \ -H "Content-Type: application/json" \ -d '{"name":"John"}'
服务端阅读 05月29日 23:47

如何用 cURL 发送 GET 和 POST 请求?

GET 用来从服务端取数据,参数通常放在 URL 查询串里;POST 用来提交数据,数据通常放在请求体里。用 cURL 时,GET 最常见的是直接请求 URL,POST 常用 -d 或 --data 传请求体。注意:curl -d 默认会发 POST,不一定非要写 -X POST。追问GET 和 POST 最大区别是什么?GET 的参数暴露在 URL 中,适合查询;POST 的数据放在 body 中,适合提交表单、JSON 或文件。GET 通常可缓存、幂等;POST 通常不缓存,也不保证幂等。-d 和 -G 一起用是什么意思?-d 默认把数据放进请求体并触发 POST;加 -G 后,cURL 会把这些参数拼到 URL 后面,仍然发 GET。实际调接口时最常用哪些参数?常用 -H 加请求头,-d 传 JSON 或表单,-i 看响应头和响应体,-I 只看响应头,-v 排查连接、TLS、重定向等问题。发送 JSON 时容易踩什么坑?最常见是忘了加 Content-Type: application/json,或者 JSON 字符串引号没转义好。另一个坑是误以为 -X POST 必须写,其实有 -d 时 cURL 已经会用 POST。写段代码# GET:查询用户curl "https://api.example.com/users?page=1&limit=10"# GET:带请求头curl -H "Authorization: Bearer token" \ https://api.example.com/users# POST:提交 JSONcurl https://api.example.com/users \ -H "Content-Type: application/json" \ -d '{"name":"张三","email":"zhangsan@example.com"}'# POST:上传文件curl https://api.example.com/upload \ -F "file=@/path/to/file.pdf"
服务端阅读 05月29日 22:54

WebRTC 如何控制音视频质量?码率/分辨率/帧率的动态调节策略是什么?

WebRTC 如何控制音视频质量?码率/分辨率/帧率的动态调节策略是什么?WebRTC 通过 GCC(Google Congest Control) 算法自动估算带宽,动态调节编码参数,核心机制:自动调节:带宽探测:发送端逐步增加码率,检测丢包率上升则回退(AIMD 策略)编码器适配:VP8/VP9/H264 编码器根据目标码率自动调整量化参数帧率调节:带宽不足时降低帧率优先保分辨率,极低带宽才降分辨率手动控制 API:const sender = pc.getSenders()[0];const params = sender.getParameters();params.encodings[0].maxBitrate = 500000; // 500kbpsparams.encodings[0].maxFramerate = 15;params.encodings[0].scaleResolutionDownBy = 2; // 分辨率减半sender.setParameters(params);音频处理:NetEQ:抖动缓冲 + PLC(丢包隐藏),平滑播放AEC:回声消除,防止扬声器声音被麦克风拾取NS/ANR:噪声抑制,过滤背景噪声AGC:自动增益控制,稳定音量视频处理:关键帧请求(PLI/FIR)应对丢包,Simulcast 发多路流供 SFU 选择。追问Simulcast 是什么?如何工作? — 同时发送多分辨率/码率流,SFU 按接收端带宽转发对应路如何检测网络质量变差? — 监听 getStats 的 packetsLost、jitterBufferDelay、availableOutgoingBitrateAEC 在什么场景下效果差? — 延迟超过 200ms、非线性失真严重、多声源场景setParameters 和 replaceTrack 有什么区别? — setParameters 调编码参数不变轨道,replaceTrack 换整个轨道(如切换摄像头)
服务端阅读 05月29日 22:54

WebRTC 安全吗?DTLS/SRTP 加密原理和常见风险有哪些?

WebRTC 安全吗?DTLS/SRTP 加密原理和常见风险有哪些?WebRTC 强制加密:所有媒体流走 SRTP,数据通道走 DTLS,密钥通过 DTLS 握手在 ICE 连接建立后协商,默认端到端加密。加密链路:信令:HTTPS/WSS 传输 SDP,信令服务器可看明文(所以选可信信令服务)媒体:DTLS 握手协商密钥 → SRTP 加密音视频包 → 中间人无法解密数据通道:DTLS 直接加密,SCTP 传输潜在安全风险:信令劫持:SDP 明文经信令服务器,恶意服务器可篡改 SDP 注入攻击者 ICE Candidate(MITM)IP 泄露:ICE Candidate 包含本地/公网 IP,即使经过 VPN 也会泄露真实 IPTURN 中继窃听:TURN 服务器可解密中继流量,需选择可信 TURN 提供商屏幕共享滥用:getDisplayMedia 无限制可能泄露敏感信息,应约束分享区域DDoS 利用:WebRTC 可被用来发起 UDP 泛洪攻击防护措施:验证远端指纹(remoteDescription.fingerprint)、限制 ICE Candidate 类型隐藏 IP、信令用 Token 鉴权。追问DTLS 和 TLS 有什么区别? — DTLS 基于 UDP,增加重传和乱序处理,握手流程类似但容忍丢包如何防止 IP 通过 ICE 泄露? — 设置 iceTransportPolicy 为 relay 仅用 TURN,或 filter 掉 host CandidateWebRTC 能做到零信任吗? — 需要 Insertable Streams 在应用层再做一层端到端加密TURN 服务器如何选择才安全? — 自建优于第三方,审计日志,限制中继流量配额
服务端阅读 05月29日 22:54

WebRTC 如何与 Socket.io 和 Node.js 后端集成?信令服务怎么设计?

WebRTC 如何与 Socket.io 和 Node.js 后端集成?信令服务怎么设计?WebRTC 本身只解决 P2P 媒体传输,信令交换(SDP Offer/Answer、ICE Candidate)必须通过独立信令通道完成,Socket.io + Node.js 是最常见组合。架构:浏览器 A 通过 Socket.io 将 SDP Offer 发给 Node.js 信令服务器 → 服务器转发给浏览器 B → B 回传 Answer → 双方交换 ICE Candidate → P2P 连接建立。核心集成点:Socket.io 信令:事件驱动,房间模型天然适合多方通话。emit/offer、on/answer、ice-candidate 三组事件即可完成信令Node.js TURN 服务:P2P 穿透失败时需中继,Node.js 可管理 TURN 服务器分配录制集成:Node.js + FFmpeg 接收 WebRTC 流转码存储,或用 MediaRecorder API 浏览器端录制权限控制:Node.js 中间件校验房间 Token,防止未授权加入典型信令流程:join room → emit('offer') → broadcast → emit('answer') → exchange ICE → RTCPeerConnection connected注意事项:Socket.io 不保证消息顺序,ICE Candidate 可能乱序到达,但 WebRTC 内部会缓存排序;大规模房间需改用 SFU(如 mediasoup)代替 Mesh。追问信令服务器能用 HTTP 代替 WebSocket 吗? — 可以但延迟高,HTTP 轮询不适合实时 ICE 交换多人通话信令如何设计? — 每对用户建立 PeerConnection,新用户加入时向房间内所有人发 Offer如何集成 mediasoup 做 SFU? — Node.js worker 管理 Router/Transport,WebRTC 端通过 produce/consume 订阅流Socket.io 和原生 WebSocket 怎么选? — Socket.io 自带房间/重连/命名空间,开发效率高;原生 WebSocket 更轻量性能更好
服务端阅读 05月29日 22:54

WebView 如何与原生应用交互?JS Bridge 原理是什么?

WebView 如何与原生应用交互?JS Bridge 原理是什么?WebView 与原生交互本质是JS 和 Native 之间的双向通信,核心方案:Native → JS:Android:evaluateJavascript(script, callback)(API 19+)iOS:evaluateJavaScript(script, completionHandler)JS → Native:URL Scheme 拦截:JS 修改 window.location = "scheme://action?params",Native 拦截 shouldOverrideUrlLoading 解析执行。兼容性最好,但 URL 长度受限prompt/alert 拦截:JS 调 prompt(),Native 在 onJsPrompt 中拦截。支持大参数,但会阻塞 JS 线程JS Bridge 注入:Native 通过 addJavascriptInterface(Android)/ WKScriptMessageHandler(iOS)向 JS 上下文注入对象,JS 直接调用原生方法。最主流的方案通信协议设计:请求:{ method: "getUserInfo", params: {}, callbackId: "cb_123" }响应:Native 执行 JS 回调函数 Bridge.callbacks["cb_123"](result)关键注意事项:安全:Android addJavascriptInterface 在 API < 17 有反射漏洞,需校验调用来源线程:Native 回调在非 UI 线程,操作 UI 需切换到主线程生命周期:页面销毁后 JS 回调可能崩溃,需清空回调队列追问三种 JS→Native 方案怎么选? — URL Scheme 兼容性好,prompt 支持大数据,注入对象最优雅,实际项目通常组合使用如何设计通用的 Bridge 协议? — 统一 method/params/callbackId,Native 端注册 Handler 映射表Bridge 通信有性能瓶颈吗? — 高频调用(如滚动事件)会有延迟,需节流或改用批量传递iOS WKWebView 和 UIWebView 交互有什么区别? — UIWebView 用 JSContext 注入,WKWebView 只能用 messageHandler + evaluateJavaScript
服务端阅读 05月29日 22:54

WebView、React Native 和 Flutter 怎么选?跨平台方案核心差异是什么?

WebView、React Native 和 Flutter 怎么选?跨平台方案核心差异是什么?| 维度 | WebView | React Native | Flutter ||------|---------|-------------|---------|| 渲染 | 系统 WebView | 原生组件 | 自绘引擎(Skia) || 语言 | HTML/JS/CSS | JavaScript | Dart || 性能 | 中低 | 中高 | 高 || 一致性 | 依赖系统内核 | 接近原生 | 像素级一致 || 生态 | Web 生态复用 | npm 生态 | Pub 生态(快速成长) || 热更新 | 天然支持 | CodePush 支持 | 需自建方案 |选择建议:内容型/运营驱动 → WebView:发版快、Web 人才多、适合高频变动的营销页交互型/团队 JS 为主 → RN:接近原生体验,复用 React 生态,适合中等复杂度应用高性能/一致性要求 → Flutter:60fps 自绘,UI 高度定制,适合动画密集或双端一致性要求高的应用注意:没有银弹,混合方案(部分 Flutter + 部分 WebView)也是常见选择。团队技术栈和招聘成本往往比技术指标更决定性。追问Flutter 自绘引擎为什么性能好? — 直接操作 Canvas 绘制,不经过原生组件树,减少桥接开销RN 的新架构有什么改进? — JSI 同步调用替代异步 Bridge,Fabric 新渲染器,TurboModule 懒加载WebView 方案最大的瓶颈是什么? — 渲染性能和交互一致性,复杂列表和手势场景体验差混合栈如何实现? — FlutterBoost / RN 容器化,原生管理页面栈,跨方案页面共存三者动态化能力如何? — WebView 最强(发版即更新),RN 支持 CodePush,Flutter 需自建 DSL 下发
服务端阅读 05月29日 22:54

WebView 能跑 PWA 吗?离线应用和 Service Worker 支持情况如何?

WebView 能跑 PWA 吗?离线应用和 Service Worker 支持情况如何?WebView 对 PWA 的支持严重受限,不能直接当作浏览器使用 PWA。Service Worker:Android WebView 从 Chrome 40+ 支持注册,但需手动启用 setJavaScriptEnabled + setDomStorageEnabled。iOS WKWebView 自 iOS 11.3 支持 Service Worker,但有限制——默认不共享浏览器 SW 缓存。离线应用核心障碍:Manifest 注册:WebView 不支持 Web App Manifest,无法安装到桌面缓存隔离:WebView 的 Service Worker 缓存与浏览器独立,不能复用后台同步:Background Sync API 在 WebView 中不可用推送通知:Push API 依赖浏览器推送通道,WebView 无法使用可行替代方案:离线包:Native 层下载资源包,WebView 拦截请求从本地返回LocalStorage / IndexedDB:可正常使用,做数据层离线App Shell 模型:首屏 HTML/CSS/JS 内置到 App,接口数据走缓存策略追问WebView 中 Service Worker 注册失败怎么排查? — 检查 HTTPS、scope 路径、SW 文件 MIME 类型是否为 application/javascript离线包如何更新? — Native 层检查版本号 diff 更新,或全量替换 zipIndexedDB 在 WebView 中有限制吗? — 存储配额因系统而异,iOS 可能低至 5MB 无提示清理如何模拟 PWA 的添加到桌面? — Native 提供 Shortcut API,结合 Deep Link 实现类似效果
服务端阅读 05月29日 22:54

WebView 中视频播放有哪些坑?如何处理全屏和自动播放?

WebView 中视频播放有哪些坑?如何处理全屏和自动播放?WebView 内嵌视频的核心问题集中在全屏切换、自动播放限制、硬件加速三方面。自动播放:多数浏览器禁止带声音自动播放。Android 需设置 mediaPlaybackRequiresUserGesture = false(API 17+),iOS WKWebView 设置 mediaTypesRequiringUserActionForPlayback = []。静音视频自动播放限制更宽松。全屏播放:HTML5 video 全屏时 Android 需实现 onShowCustomView / onHideCustomView 回调,将视频 SurfaceView 提升到原生层展示。iOS 的 video 默认支持内联全屏,playsinline 属性控制是否内联。硬件加速:Android 必须在 Manifest 中开启 hardwareAccelerated,否则视频黑屏有声音无画面。关键注意事项:同层渲染:视频层级高于 WebView,会遮挡其他 HTML 元素,需同层渲染方案(腾讯 X5 内核支持)内存释放:页面销毁前必须调用 video.pause() 释放解码器Cookie 传递:视频 CDN 鉴权 Cookie 可能未同步到 MediaPlayer画中画:Android 8+ 支持 PiP,需在 onUserLeaveHint 中 enterPictureInPictureMode追问视频黑屏有声音怎么排查? — 检查硬件加速是否开启,SurfaceView 层级是否被覆盖如何实现视频内联播放? — iOS 加 playsinline 属性,Android 设置 setMediaPlaybackRequiresUserGesture同层渲染原理是什么? — X5 内核将视频帧绘制到 WebView 纹理上,统一渲染层级视频 Cookie 鉴权失败怎么办? — 从 WebView CookieManager 读取,通过 Header 传给 MediaPlayer
服务端阅读 05月29日 22:54

WebView 如何拦截和修改网络请求?shouldInterceptRequest 能做什么?

WebView 如何拦截和修改网络请求?shouldInterceptRequest 能做什么?Android 用 shouldInterceptRequest(WebViewClient),iOS 用 WKURLSchemeHandler(WKWebView)拦截请求,可读取 URL/Headers 并返回自定义响应。Android shouldInterceptRequest:非 UI 线程回调,不可操作 View返回 WebResourceResponse 即替换原始响应,返回 null 走默认逻辑仅拦截 GET/POST 等 HTTP 请求,不拦截 XHR fetch(部分版本)iOS WKURLSchemeHandler:需注册自定义 Scheme(如 custom://),https scheme 无法拦截实现 startURLSchemeTask / stopURLSchemeTask返回数据通过 didReceiveResponse + didReceiveData 回调核心用途:本地缓存替换、请求头注入(Token)、CDN 域名替换、离线包加载。注意事项:性能:拦截所有请求会拖慢页面,需按 URL 前缀过滤线程安全:Android 回调在非 UI 线程,不能直接操作 UIHTTPS 限制:iOS 不允许拦截 https,必须用自定义 Scheme缓存一致:替换响应后需正确设置 mimeType 和 encoding追问如何只拦截特定域名请求? — URL 前缀判断,命中才处理,其余返回 null拦截后如何修改请求头? — Android 无法直接修改请求头,需重新发 HttpURLConnection 并附带头信息离线包方案如何实现? — 拦截请求后从本地 Zip 读取文件返回,版本号控制更新iOS 为什么不能拦截 https? — Apple 安全策略限制,需改用自定义 Scheme 或 ATS 例外
服务端阅读 05月29日 22:54

WebView 如何与原生页面混合使用?混合栈有哪些坑?

WebView 如何与原生页面混合使用?混合栈有哪些坑?WebView 与原生页面混合使用指在同一 App 中交替展示 H5 页面和原生页面,形成混合导航栈。核心方案:容器模式:Native 提供 WebView 容器 Activity/ViewController,H5 页面作为容器内容路由分发:URL Scheme 或 JS Bridge 指令决定跳转原生还是 WebView栈管理:统一路由层维护混合栈,处理前进/后退的页面类型判断关键注意事项:回退逻辑:WebView 内部有历史栈,按返回键需先回退 WebView 历史,空了再 pop 原生栈生命周期:WebView 页面切后台后 JS 定时器/回调可能丢失,需 visibilitychange 监听内存泄漏:WebView 引用未及时销毁,Android 需在 onDestroy 中移除并置空状态同步:登录态、用户信息需在原生和 H5 间实时同步,避免态不一致转场体验:Native↔H5 切换易出现白屏闪烁,可用预加载 + 转场动画缓解追问混合栈如何统一管理路由? — 封装 Router 中间层,registerNativeRoute / registerWebViewRoute,跳转时根据类型分发WebView 页面如何感知原生返回事件? — 注入 JS Bridge 的 onBackPress 回调,返回 true 拦截默认行为如何避免 WebView 重复创建? — 复用 WebView 池,页面切换时 loadUrl 替换内容而非新建实例混合栈的埋点如何统一? — 定义统一事件协议,Native 和 H5 各自上报到同一埋点通道
服务端阅读 05月29日 22:54

Canvas fillText 和 strokeText 有什么区别?如何实现高级文本效果?

Canvas fillText 和 strokeText 有什么区别?如何实现高级文本效果?fillText 绘制实心文字,strokeText 绘制文字轮廓(空心),两者共用 font、textAlign、textBaseline 属性。调用签名:fillText(text, x, y [, maxWidth]),maxWidth 超出时自动压缩。关键要点:同时使用:先 strokeText 再 fillText,可做出描边+填充效果,避免填充被描边覆盖measureText:获取文本宽度做布局计算,返回 TextMetrics 对象maxWidth:文本超宽时等比缩放,不截断多行文本:Canvas 不支持自动换行,需手动按 \n 分割后逐行 fillText中文渲染:指定支持中文的字体族,否则可能回退为系统默认ctx.font = 'bold 24px sans-serif';ctx.strokeStyle = '#333';ctx.lineWidth = 2;ctx.strokeText('描边文字', 50, 50);ctx.fillStyle = '#e74c3c';ctx.fillText('填充文字', 50, 80);追问如何实现文本自动换行? — 按字符逐个累加 measureText 宽度,超过容器宽度时截断换行strokeText 描边模糊怎么办? — 设置 lineJoin 为 round,或在 fillText 之前 strokeText 避免叠加伪影如何绘制竖排文字? — 逐字绘制并递增 y 坐标,或使用 CSS WritingMode 配合 OffscreenCanvasmeasureText 能获取高度吗? — 标准 TextMetrics 已支持 actualBoundingBoxAscent/Descent,兼容性需注意高 DPI 屏幕文字模糊如何解决? — Canvas 尺寸乘 devicePixelRatio,CSS 尺寸不变,scale 后绘制
服务端阅读 05月29日 22:54

axios 如何实现并发请求和取消请求?代码怎么写?

axios 的并发和取消分别基于 Promise.all 和 AbortController/CancelToken。并发请求: 使用 Promise.all 同时发起多个请求,全部成功返回结果数组,任一失败则整体失败。axios.all 已废弃(v0.27+),直接用 Promise.all。需要逐个处理结果用 Promise.allSettled,无论成功失败都返回每个请求的状态。// 并发请求const [users, posts] = await Promise.all([ axios.get('/api/users'), axios.get('/api/posts')]);// 容错并发const results = await Promise.allSettled([ axios.get('/api/a'), axios.get('/api/b')]);results.forEach(r => { if (r.status === 'fulfilled') handleData(r.value.data);});取消请求: 新方案用 AbortController(v0.22+推荐),旧方案 CancelToken 已废弃。AbortController 是浏览器原生 API,与 fetch 通用。// AbortController 取消const controller = new AbortController();axios.get('/api/data', { signal: controller.signal });// 取消controller.abort();// 封装自动取消:同一接口新请求自动取消旧请求const pending = new Map();function fetchWithCancel(url) { pending.get(url)?.abort(); const ctrl = new AbortController(); pending.set(url, ctrl); return axios.get(url, { signal: ctrl.signal }).finally(() => pending.delete(url));} 追问: Promise.all 和 Promise.allSettled 在错误处理上的区别是什么? 如何控制并发数量(如最多同时 3 个请求)? 取消请求后 axios 抛出的是什么错误?如何区分取消和真正的请求失败? 路由切换时如何批量取消未完成的请求? CancelToken 为什么被废弃?它和 AbortController 的实现原理有什么不同?
服务端阅读 05月29日 22:54

axios 文件上传下载怎么做?进度监控和 CSRF 防护如何实现?

axios 的高级特性主要有 文件上传下载、进度监控、CSRF 防护、实例封装。文件上传: 使用 FormData 构建请求体,设置 Content-Type: multipart/form-data(axios 自动识别 FormData 并设置)。分片上传需手动将文件切片(Blob.slice),逐片上传并在后端合并。上传示例:const form = new FormData(); form.append('file', fileBlob); axios.post('/upload', form)。文件下载: 配置 responseType: 'blob' 获取二进制数据,通过 URL.createObjectURL(blob) 创建临时链接,触发 <a> 标签下载。大文件下载注意内存,可用流式处理(Node 环境)。进度监控: 上传用 onUploadProgress,下载用 onDownloadProgress,回调参数包含 loaded 和 total,计算百分比:Math.round(loaded / total * 100)。底层基于 XMLHttpRequest 的 progress 事件,Node 环境不支持。CSRF 防护: 配置 xsrfCookieName 和 xsrfHeaderName,axios 自动从 Cookie 读取 XSRF-Token 并写入请求头。后端需在登录时设置 Set-Cookie: XSRF-TOKEN=xxx; Path=/。实例封装: axios.create() 创建独立实例,拥有自己的拦截器、默认配置和适配器,适合多 API 服务的项目隔离配置。 追问: 分片上传如何实现断点续传?需要后端配合什么接口? onUploadProgress 在 Node 环境下为什么不生效?有替代方案吗? 大文件下载如何避免浏览器内存溢出? axios.create 创建的实例和全局 axios 对象的拦截器是共享的吗? XSRF-Token 的 Cookie 为什么不能设 HttpOnly?这和 XSS 风险如何权衡?
服务端阅读 05月29日 22:54

axios 和 fetch 有什么区别?什么时候该用 axios 而非 fetch?

axios 和 fetch 的核心区别在 错误处理、拦截器、请求取消、数据转换、兼容性 五个方面。错误处理: fetch 只有网络故障才 reject,HTTP 4xx/5xx 仍走 resolve,需手动检查 response.ok;axios 自动将 4xx/5xx 转为 reject,错误处理更符合直觉。拦截器: axios 内建请求/响应拦截器,统一添加 Token、处理错误码;fetch 无拦截器,需手动包装或用第三方库。请求取消: axios 支持 CancelToken 和 AbortController;fetch 只支持 AbortController。axios 的超时配置(timeout)是内建的,fetch 需自己用 AbortController + setTimeout 实现。数据转换: axios 自动 JSON 转换(请求时 stringify、响应时 parse);fetch 需手动调用 response.json()。axios 自动处理 URL 编码和 FormData。兼容性: fetch 是浏览器原生 API,无依赖;axios 约 13KB gzipped。fetch 在旧浏览器需 polyfill(如 whatwg-fetch)。选 axios 的场景: 需要拦截器、自动错误处理、超时控制、请求/响应转换、取消请求。选 fetch 的场景: 追求零依赖、简单请求、Service Worker 中使用、项目已在用 SWR/React Query 等上层库。 追问: fetch 的 credentials: 'include' 和 axios 的 withCredentials: true 行为是否一致? fetch 如何实现和 axios 拦截器类似的功能? 在 Service Worker 中为什么推荐用 fetch 而非 axios? axios 的响应拦截器能拿到原始的 Response 对象吗? React Query 或 SWR 底层用的是 axios 还是 fetch?能切换吗?
服务端阅读 05月29日 22:54

axios 性能优化有哪些技巧?如何减少冗余请求?

axios 性能优化围绕 请求去重、缓存、并发控制、体积优化 四个维度。请求去重: 对同一接口的并发请求做合并,避免重复发送。实现方式:在请求拦截器中用 URL+参数生成 key,维护一个 Map 记录正在进行的请求,相同 key 的请求复用同一个 Promise,响应后删除 key。也叫"请求锁"或"请求合并"。请求缓存: 对不常变的数据(配置信息、字典表)做本地缓存。在响应拦截器中按 URL+参数缓存响应,设置 TTL 过期。也可用 HTTP 缓存头(Cache-Control、ETag)配合浏览器缓存,axios 的 adapter 可实现自定义缓存适配器。并发控制: 使用 Promise.all 并发请求提升加载速度;对大量并发用并发池控制(如 p-limit),避免浏览器同域 6 连接限制导致的排队。批量接口优先用后端聚合 API,减少请求次数。体积优化: 开启 gzip 压缩(服务端配置);请求参数精简,只传必要字段;响应数据按需获取(分页、字段过滤);大文件上传用分片上传减少超时风险。 追问: 请求去重的 Map 在请求失败时如何清理?避免后续请求被阻塞? 自定义缓存 adapter 如何处理 POST 请求的缓存策略? 浏览器同域并发连接限制对 axios 有什么影响?如何绕过? 如何实现 axios 请求的优先级队列? 分片上传的断点续传如何在 axios 中实现?
服务端阅读 05月29日 22:54

axios 存在哪些安全风险?如何防范 XSS 和 CSRF 攻击?

axios 的安全风险集中在 CSRF、XSS、敏感数据泄露、SSRF 四个方面。CSRF 防护: axios 内置 CSRF 防护,通过 xsrfCookieName 和 xsrfHeaderName 配置自动从 Cookie 读取 Token 并附加到请求头。后端需设置 Set-Cookie: XSRF-TOKEN=xxx,前端配置 axios.defaults.xsrfCookieName = 'XSRF-TOKEN'。对于 SameSite Cookie 策略,建议后端设置 SameSite=Strict 或 Lax 作为双重保障。XSS 防护: axios 本身不执行 HTML,但返回数据若直接插入 DOM(如 v-html、dangerouslySetInnerHTML)会导致 XSS。必须对响应数据做转义,或使用 DOMPurify 净化。另外避免在 URL 参数中拼接用户输入,防止反射型 XSS。敏感数据泄露: Token 不要存 localStorage(XSS 可读取),优先存 HttpOnly Cookie;请求拦截器中不要把 Token 打印到日志;响应拦截器中敏感字段(密码、密钥)应在日志中脱敏。SSRF 防护: 服务端使用 axios 时,若 URL 来自用户输入,需校验目标地址,禁止请求内网 IP(127.0.0.1、10.x.x.x、192.168.x.x),使用白名单域名策略。 追问: axios 的 XSRF 防护机制在前后端分离架构下如何实现? SameSite Cookie 的 Strict 和 Lax 模式对 CSRF 防护有什么影响? HttpOnly Cookie 方案在跨域场景下如何配置 CORS? 如何对 axios 响应数据做自动化脱敏? SSRF 攻击中如何绕过 IP 黑名单?白名单方案怎么设计?