面试题手册

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

服务端阅读 05月29日 22:40

区块链有哪些安全威胁?51%攻击和双花攻击怎么防?

三大威胁:51%攻击——控制超半数算力/权益后可回滚交易;双花攻击——同一笔钱花两次;智能合约漏洞——重入、溢出、权限缺失。51%防御:PoS 中 slash 没收质押金让攻击成本远超收益。双花防御:等 6 个确认(BTC)或 finalize(ETH PoS 约 12 分钟)。合约防御:Checks-Effects-Interactions 模式、OpenZeppelin 库、审计。追问51%攻击在 PoS 链上更容易还是更难?更难。PoW 攻击后算力还在手上无损失。PoS 攻击被发现后质押金被 slash 没收,经济损失巨大且不可逆。交易所如何防双花?不信任 0 确认交易。大额等 6+ 确认,用区块链监控检测重组。女巫攻击和 51%攻击什么关系?女巫攻击是创建大量虚假身份影响共识,是 51%攻击的前提手段之一。PoW/PoS 都通过经济成本抑制。MEV 算安全威胁吗?算。前端运行抢跑、三明治攻击让用户成交价变差。Flashbots 等私有内存池将 MEV 收益转移给用户,但不能完全消除。形式化验证能替代审计吗?不能。只能验证你写出 spec 的部分,业务逻辑漏洞不违反 spec 就检测不到。验证+审计+测试网+Bug Bounty 四层防护。
服务端阅读 05月29日 22:40

区块链用了哪些密码学技术?哈希、签名和 Merkle Tree 各起什么作用?

三大核心:哈希函数(SHA-256/Keccak256)保证数据完整性,区块头哈希链接形成链;数字签名(ECDSA/EdDSA)私钥签名公钥验证,证明交易身份;Merkle Tree 只需 log(n) 个哈希即可证明某笔交易在区块中(SPV 验证)。三者协作:签名保证身份,哈希保证不可篡改,Merkle 保证高效验证。追问SHA-256 和 Keccak256 有什么区别?SHA-256 是 NIST 标准(比特币),Keccak256 是 SHA-3 竞赛获胜者(以太坊)。算法完全不同:SHA-2 是 Merkle-Damgard 构造,Keccak 是海绵构造。为什么不直接用公钥当地址?公钥 64 字节太长。以太坊地址=keccak256(pubKey) 后 20 字节,比特币地址=Base58Check(SHA-256+RIPEMD-160(pubKey))。缩短地址减少链上存储。Merkle 证明怎么验证?提供目标哈希+每层兄弟哈希,逐层向上组合计算根哈希,对比是否等于已知根。只需 log2(n) 个哈希值。零知识证明怎么用?zk-SNARK/zk-STARK:证明我知道 X 而不透露 X。应用:Zcash 隐私交易、zkRollup 批量证明、身份验证(证明年满 18 岁不暴露生日)。量子计算会破解这些密码吗?ECDSA 会被 Shor 算法破解。SHA-256 只被 Grover 算法削弱(等价密钥长度减半)。抗量子方案:签名用 lattice-based,哈希加倍长度。以太坊已有抗量子路线图。
服务端阅读 05月29日 22:40

Service Worker 调试有哪些常用方法和工具?

Chrome DevTools 是主战场:Application > Service Workers 面板可查看注册状态、更新、卸载;Sources 面板可打断点;Network 面板勾选 Bypass for network 绕过 SW。Console 里 self.addEventListener(fetch, e => console.log(e.request.url)) 打日志最直接。开发时勾选 Update on reload 避免手动等待激活。追问SW 更新后页面还是旧逻辑?SW 更新走 install→wait→activate。wait 阶段等旧 SW 退出才激活。开发时勾选 Update on reload;生产用 skipWaiting()+clients.claim() 立即接管,但可能导致不兼容。推荐:显示提示让用户主动刷新。如何模拟离线场景?DevTools Network 选 Offline,或 Application > Service Workers 勾选 Offline。也可用 navigator.onLine 检测。注意:离线需要 SW 有缓存策略否则白屏。SW 里 console.log 看不到?SW 运行在独立线程,日志在 Sources > Service Worker 专用控制台。或在 Application > Service Workers 点 inspect 打开专用 DevTools。缓存没命中怎么排查?打印 caches.match(request) 结果:命中返回 Response,未命中 undefined。常见原因:URL 查询参数不一致、request method 不匹配(默认只匹配 GET)、vary 头导致缓存分裂。生产环境如何监控 SW 异常?self.addEventListener(error/unhandledrejection, …) 捕获异常上报。关注注册失败率和缓存命中率。Workbox 的 workbox-google-analytics 可追踪离线 PV。
服务端阅读 05月29日 22:40

DeFi 是什么?核心协议和流动性挖矿怎么运作?

DeFi 是在区块链上用智能合约替代传统金融中介的开放金融体系。三大核心协议:DEX(Uniswap 用 AMM 自动做市取代订单簿)、借贷协议(Aave/Compound,超额抵押借款,利率由供需算法决定)、衍生品(dydx 链上永续合约)。流动性挖矿:用户向资金池提供流动性获得 LP 代币+治理代币奖励。追问AMM 和订单簿哪个好?AMM 无需撮合随时可交易,适合长尾资产。但大额滑点大且有无常损失。订单簿体验接近 CEX,但需要链下撮合引擎。什么是无常损失?LP 提供两种代币后价格比例变化,LP 持有的资产价值低于简单持有两种代币。差值即无常损失。2 倍价格变化约 5.7% 损失。超额抵押为什么不高效?借 100 美元需存 150 美元抵押品。闪电贷解决了这个问题——同一交易内借还无需抵押,但只能用于原子操作。DeFi 的系统性风险?合约漏洞、预言机操纵、治理攻击、可组合性传染。2022 年 Celsius/Luna 崩盘是典型传染案例。流动性挖矿还有利可图吗?蓝筹 APR 从 2020 年 100%+ 降到个位数。现在要看:挖矿收益+交易手续费+代币增值预期综合评估。纯通胀模式不可持续。
服务端阅读 05月29日 22:40

Zustand 有哪些常用中间件?怎么用?

Zustand 中间件就是高阶函数,用函数组合串联:create(devtools(persist(immer((set) => …)))) 从内到外依次包裹。常用 5 个:persist 持久化到 storage;immer 支持 mutable 写法更新嵌套对象;devtools 接入 Redux DevTools;subscribeWithSelector 精确订阅子属性变化;combine 合并多个 slice。追问中间件的执行顺序有讲究吗?有。从内到外:最内层的先执行。devtools(persist(immer(…))) 意味着 immer 先处理,再 persist,最后 devtools 记录。顺序反了会出错。immer 和普通 set 的性能差异?immer 用 Proxy 追踪变更,有额外开销但通常可忽略。大多数项目 immer 的开发体验收益远大于性能损失。自定义中间件怎么做日志?拦截 set 参数,前后打印状态即可。生产环境用 devtools 替代手动日志。persist 的 partialize 怎么用?partialize: (state) => ({ token: state.token, theme: state.theme }) 只持久化指定字段,避免把临时 UI 状态也存进 storage。subscribeWithSelector 解决什么问题?默认 useStore(s => s.items) 用 Object.is 比较,对象每次都是新引用所以总是重渲染。subscribeWithSelector 让你可以用 shallow 比较或自定义 equalityFn。
服务端阅读 05月29日 22:40

PoW、PoS 和 DPoS 共识机制有什么区别?优缺点各是什么?

PoW:算力竞争出块,安全但耗能(BTC 每笔约 1000 kWh)。PoS:持币量决定出块权,节能 99.9% 但有质押中心化风险。DPoS:投票选验证者(如 EOS 21 节点),出块快但去中心化程度低。选型:极致安全选 PoW,效率可扩展选 PoS,高 TPS 选 DPoS。Ethereum 已从 PoW 转为 PoS。追问PoS 不是更容易富者愈富吗?是的,这是核心争议。缓解:设质押上限、slashing 惩罚、流动性质押降低门槛。完全消除不现实,但比 PoW 的矿机垄断门槛低。DPoS 为什么被批评不够去中心化?21 个节点就能控制整条链,容易串谋。选民冷漠也加剧集中。支持者认为出块快(0.5s)、吞吐高,适合特定商业场景。Ethereum 为何选 PoS 不选 DPoS?Casper FFG 允许任意 32 ETH 质押者参与(超 50 万验证者),远比 21 节点分散。DPoS 的高 TPS 代价是牺牲去中心化,Ethereum 选 L2 Rollup 扩容。PoW 的 51%攻击成本怎么算?比特币约需 200 万台矿机,成本超 50 亿美元+每日电费数百万。攻击后 BTC 价格暴跌,矿机变废铁。小算力链就没有这个保障。还有其他共识机制吗?PoA(权威证明,联盟链)、PoH(历史证明,Solana)、BFT 类(Tendermint,2/3 投票确认,确定性快但不适合大规模验证者)。
服务端阅读 05月29日 22:40

Service Worker 如何实现跨域资源的缓存?

Service Worker 可以缓存跨域资源,但有 CORS 限制:fetch 跨域请求默认不发 credentials,响应必须包含 Access-Control-Allow-Origin 头,否则浏览器拦截无法缓存。opaque response(no-cors 模式下)可缓存但无法读取内容,且计入 7 倍缓存配额,最多存活 7 天(Chrome)。CDN 支持 CORS 时务必用 cors 模式。追问opaque response 有什么坑?status 始终为 0,无法读取 body 也不能判断缓存是否有效。占用 7 倍缓存配额,7 天后自动清理。CDN 支持 CORS 务必用 cors 模式。如何让第三方 CDN 走 CORS?CDN 侧配置 Access-Control-Allow-Origin。SW 侧 fetch 时 mode: cors(默认值)。CDN 不支持 CORS 只能退回 no-cors。缓存跨域字体和图片有什么区别?字体必须 CORS 才能被 @font-face 使用(浏览器安全策略)。图片/CSS/JS 不受此限制,但 SW 缓存时 opaque response 仍有 7 天限制。Stale-While-Revalidate 怎么用?caches.match 返回缓存,后台 fetch 更新缓存。先快后新,下次请求就是新数据。跨域 API 的缓存怎么处理?API 通常带 CORS 头可正常缓存。但带 Authorization 的请求不能缓存到共享 Cache,会泄露用户数据。私有数据只缓存内存或 SessionStorage。
服务端阅读 05月29日 22:40

Zustand 中如何用 TypeScript 确保类型安全?

定义 interface StoreState 声明所有状态和 action 类型,create()((set) => …) 传入泛型。关键:set((state) => ({ count: state.count + 1 })) 这种函数式更新需要泛型才能正确推断 state 类型。Action 也写在 interface 里,类型签名一目了然。追问set 的类型怎么写才不报错?set 接受 Partial | ((state: StoreState) => Partial)。用 immer middleware 时写法是 set((state) => { state.count += 1 }),不需要返回值。selector 类型怎么保证?useStore(s => s.count) 自动推断为 number。复杂 selector 用 shallow 比较避免重复渲染。不要写 useStore 丢失类型。persist middleware 的泛型怎么传?persist 单独传泛型,和 create 的泛型一致。漏传泛型会导致 set 内部类型丢失。多个 slice 怎么组织类型?按功能拆分文件,每个 slice 导出自己的 interface 和 create,主 store 用组合模式合并。和 Jotai 的类型体验比呢?Jotai 的 atom 天然类型安全,不需要额外泛型。Zustand 需要手动传泛型但更灵活。两者都能做到完全类型安全。
服务端阅读 05月29日 22:40

Zustand 和 Redux 有什么区别?选哪个?

核心区别:Zustand 不需要 Provider 包裹、不需要 reducer/action 模板代码、store 直接用 set 修改。Redux 需要 Provider + createSlice + useDispatch + useSelector 四件套。Zustand 1KB vs Redux+RTK 30KB。选型:新项目/中小团队选 Zustand,已有 Redux 代码库或需要强约束选 Redux。追问Zustand 没有 DevTools 吗?有。import { devtools } from zustand/middleware,用法和 Redux DevTools 一样,时间旅行、action 日志都支持。Redux 的 middleware 体系 Zustand 怎么替代?Zustand 用函数组合替代:create(devtools(persist(immer((set) => …)))) 一行串联。异步不需要 thunk/saga,直接在 action 里 async/await。大型项目 Redux 更稳吗?Redux 的约束在大型团队中减少出错概率。但 Zustand 配合 TypeScript + selector 约定也能达到类似效果。关键是团队规范。能混用吗?可以但不推荐——两套模式增加认知负担。迁移建议:新模块用 Zustand,旧模块保持 Redux,逐步替换。Immer middleware 和 RTK 的区别?都是用 Immer 实现不可变更新,语法几乎一致,底层都是 produce。区别只在包装层。
服务端阅读 05月29日 22:40

React Native 中如何使用 Zustand 管理状态?

和 Web 端完全一样——npm install zustand,create((set) => ({ … })) 创建 store,组件里 useStore(selector) 读取。Zustand 不依赖 DOM API,纯 JS 实现,React Native 直接能用。唯一需要注意的是持久化:Web 用 localStorage,RN 用 mmkv 或 AsyncStorage,配合 zustand/middleware 的 persist 中间件传入不同的 storage adapter。追问Zustand 和 Redux 在 RN 中哪个更合适?Zustand。RN 对包体积敏感,Zustand 1KB vs Redux+RTK 约 30KB。API 更简洁,不需要 Provider 包裹根组件。新项目优先 Zustand。如何做持久化存储?用 MMKV 而非 AsyncStorage——MMKV 同步读写,快 30 倍。persist 中间件传入 createJSONStorage(() => mmkvStorage) 即可。关键字段(token、用户偏好)必须持久化。多个页面共享状态会重复渲染吗?用 selector 精确订阅就不会。useStore(s => s.token) 只在 token 变化时重渲染。切忌 useStore() 全量订阅。后台被系统杀掉 store 会丢吗?没做持久化的会丢。RN 端内存回收后 JS 上下文重建,store 恢复初始值。关键字段必须 persist。导航中需要传递 store 吗?不需要。Zustand 是全局单例,任何组件直接 useStore 即可,不用像 Context 那样逐层传递。