首页/新闻资讯/正文详情

Node.js 零依赖实现 API 限流:X-Forwarded-For 的坑我替你踩完了

发布时间:2026/9/26 2:25:23 来源:云帆数科 栏目:资讯中心
Node.js 零依赖实现 API 限流:X-Forwarded-For 的坑我替你踩完了
前言给网站做 favicon常规路子是找在线生成器或者npm install sharp/png-to-ico一把梭。但我的场景比较刁部署在一台零依赖的 Node 服务器上整个项目连package.json都没有为一个 4KB 的图标引入图像库有点杀鸡用牛刀。于是我研究了一下 PNG 和 ICO 的文件格式发现这俩格式简单得出奇——纯 Node 内置模块Buffer zlib就能手写一个 PNG 编码器配上一个用有向距离场SDF画圆角矩形的小渲染器150 行代码搞定。最终效果输入三个参数尺寸、两种渐变色输出一个渐变底 白色圆角工具块图案的.ico浏览器、搜索引擎站点图标Google 搜索结果里的 favicon都能正常识别。我的五个站点用了同一套代码、不同主色生成了一组家族脸图标。先看成品node gen_favicon.js out.ico 55,138,221 91,157,249生成 32×32 的 ICO蓝橙渐变底四个白色圆角小块 2×2 排列。改两个 RGB 参数就能换配色。第一步理解 PNG 文件结构PNG 一个 8 字节签名 若干个块chunk。我们只需要三块块作用IHDR宽、高、位深、颜色类型等头信息13 字节定长IDAT像素数据zlib 压缩后的 RGBAIEND结束标记空块每个 chunk 的结构[4字节长度][4字节类型][数据][4字节CRC32校验]难点只有一个CRC32。好消息是 zlib 内置了constzlibrequire(zlib);constcrc32(buf)zlib.crc32?zlib.crc32(buf):softCrc32(buf);// Node 22 自带 zlib.crc32低版本用查表法兜底第二步手写 PNG 编码器constzlibrequire(zlib);functionchunk(type,data){constlenBuffer.alloc(4);len.writeUInt32BE(data.length);consttypeBufBuffer.from(type,ascii);constcrcBuffer.alloc(4);crc.writeUInt32BE(zlib.crc32(Buffer.concat([typeBuf,data]))0);returnBuffer.concat([len,typeBuf,data,crc]);}functionencodePNG(w,h,rgba){// IHDR: 位深8 颜色类型6 RGBAconstihdrBuffer.alloc(13);ihdr.writeUInt32BE(w,0);ihdr.writeUInt32BE(h,4);ihdr[8]8;// bit depthihdr[9]6;// color type RGBA// IDAT: 每行前面加 1 字节过滤器 0None再整块 zlib 压缩conststridew*4;constrawBuffer.alloc((stride1)*h);for(lety0;yh;y){raw[y*(stride1)]0;// filter: Nonergba.copy(raw,y*(stride1)1,y*stride,(y1)*stride);}constidatzlib.deflateSync(raw,{level:9});returnBuffer.concat([Buffer.from([0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a]),// 签名chunk(IHDR,ihdr),chunk(IDAT,idat),chunk(IEND,Buffer.alloc(0)),]);}就这么几十行一个合规的 PNG 编码器完成了。踩坑提醒IDAT 的像素数据每行开头必须有一个 filter 字节哪怕你不用任何过滤器也要写 0漏了它 zlib 能压过去、浏览器却解码出一条条斜纹——这是我调了半小时才发现的特色。第三步用 SDF 画圆角矩形位图绘制最朴素的思路是逐像素判断我在不在形状里。圆角矩形用有向距离场来做非常优雅// 点 (px,py) 到圆角矩形中心距离场r 为圆角半径// 返回值 0 表示在矩形内部0 表示在外部数值≈到边缘的距离functionsdfRoundRect(px,py,hw,hh,r){constqxMath.abs(px)-hwr;constqyMath.abs(py)-hhr;constaxMath.max(qx,0),ayMath.max(qy,0);returnMath.hypot(ax,ay)Math.min(Math.max(qx,qy),0)-r;}有了它边缘抗锯齿也顺手解决了像素中心距离在[-1, 1]之间的按距离线性混合透明度边缘就是平滑渐变而不是锯齿楼梯。渲染主体先画一个渐变底对角线线性插值两色再叠四块白色圆角小矩形functionrender(size,c1,c2){constbufBuffer.alloc(size*size*4);constpadsize*0.14;// 外边距constgapsize*0.06;// 块间距constcell(size-pad*2-gap)/2;consthalfcell/2;constrcell*0.28;// 圆角半径constcenters[[-1,-1],[1,-1],[-1,1],[1,1],].map(([sx,sy])[size/2sx*(halfgap/2),size/2sy*(halfgap/2)]);for(lety0;ysize;y){for(letx0;xsize;x){consti(y*sizex)*4;// 渐变底对角线constt(xy)/(2*size-2);letRc1[0](c2[0]-c1[0])*t;letGc1[1](c2[1]-c1[1])*t;letBc1[2](c2[2]-c1[2])*t;letA255;// 叠加白色块任一块命中即白lethit1e9;for(const[cx,cy]ofcenters){hitMath.min(hit,sdfRoundRect(x-cx,y-cy,half,half,r));}if(hit1){constalphaMath.min(1,Math.max(0,(1-hit)/2));// 抗锯齿R255*alphaR*(1-alpha);G255*alphaG*(1-alpha);B255*alphaB*(1-alpha);}buf[i]R|0;buf[i1]G|0;buf[i2]B|0;buf[i3]A;}}returnbuf;}第四步包一层 ICO 壳ICO 格式比想象中还简单一个 6 字节头 一条 16 字节目录项 原始 PNG 数据。现代 ICO 支持内嵌 PNG256×256 内都合法不用再写 BMP 行序转换functionwrapICO(png){constheadBuffer.alloc(6);head.writeUInt16LE(0,0);// 保留位head.writeUInt16LE(1,2);// 类型1 图标head.writeUInt16LE(1,4);// 图像数量constdirBuffer.alloc(16);dir[0]32;dir[1]32;// 宽高0 表示 256dir[2]0;dir[3]0;// 调色板dir.writeUInt16LE(1,4);// 色彩平面dir.writeUInt16LE(32,6);// 位深dir.writeUInt32LE(png.length,8);// 数据大小dir.writeUInt32LE(22,12);// 数据偏移 6 16returnBuffer.concat([head,dir,png]);}组装入口constoutprocess.argv[2]||favicon.ico;constparse(s)s.split(,).map(Number);constc1parse(process.argv[3]||55,138,221);constc2parse(process.argv[4]||91,157,249);require(fs).writeFileSync(out,wrapICO(encodePNG(32,32,render(32,c1,c2))));console.log(OK -,out);实用建议多尺寸怎么办严格的 favicon 规范建议提供 16/32/48 三档。做法是把三个尺寸各自encodePNG后在 ICO 里放三条目录项把wrapICO里的数量改成 3、循环写目录项即可代码模式完全一样。我的实践里单 32×32 在 Chrome/Edge/Google 搜索结果里显示都正常48 以上的场景PWA、桌面快捷方式才需要补。总结PNG 编码没有想象中神秘签名 IHDR/IDAT/IEND 三个 chunk CRC32zlib 自带IDAT 每行的 filter 字节是最隐蔽的坑SDF 是位图绘制圆角形状 抗锯齿的优雅解法ICO 现代格式直接内嵌 PNG外壳只有 22 字节完整代码约 130 行零依赖Node 18 直接跑。适合的场景CI/CD 里动态生成图标、给批量站点生成同款不同色的图标家族、或者单纯想搞懂图片文件格式。完整可运行源码我整理在文末附件改配色只需要动两个 RGB 参数。有问题欢迎评论区交流。

相关推荐

macOS 27 自带了一套离线的 AI 模型
macOS 27 自带了一套离线的 AI 模型

激活>> sudo fm licensePassword:YOU HAVE NOT AGREED TO THE APPLE FOUNDATION MODELS CLI LEGAL NOTICE & TERMS.YOU MUST AGREE TO THE TERMS BELOW IN ORDER TO USE APPLE FOUNDATION MODELS CLI.LEGAL NOTICE & TERMSPLEASE READ THESE TERMS CAREFULLY BEF… · 2026/9/26 2:25:17

基于号段表的手机归属地查询:Excel数据清洗、MySQL导入与Python工具实现
基于号段表的手机归属地查询:Excel数据清洗、MySQL导入与Python工具实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 2:25:11

RocketRide tool_python 节点实战:用 RestrictedPython 沙箱为 Agent 提供受控代码执行能力
RocketRide tool_python 节点实战:用 RestrictedPython 沙箱为 Agent 提供受控代码执行能力

【免费下载链接】rocketride-server High-performance AI pipeline engine with a C core and 50 Python-extensible nodes. Build, debug, and scale LLM workflows with 13 model providers, 8 vector databases, and agent orchestration, all from your IDE. Includes VS C… · 2026/9/26 2:25:11

Eclipse添加JSLint插件:版本兼容与安装避坑指南
Eclipse添加JSLint插件:版本兼容与安装避坑指南

简介:面向Eclipse使用者的JSLint插件集成资源,专注解决JavaScript开发中缺少实时静态检查、代码质量难以把控的问题。JSLint由Douglas Crockford创建,能够系统扫描脚本中的语法隐患、不良模式与风格分歧,帮助开发者在编写阶段及时… · 2026/9/26 22:40:51

CommVault NOCATALOG模式Oracle备份与恢复实战指南
CommVault NOCATALOG模式Oracle备份与恢复实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 22:40:51

Codex 拿到前端启动模板后,我会先看这 6 个失败信号:TaoToken 配置排查清单
Codex 拿到前端启动模板后,我会先看这 6 个失败信号:TaoToken 配置排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 22:40:45

2021华为杯D题抗乳腺癌药物建模:特征选择与回归分类实战
2021华为杯D题抗乳腺癌药物建模:特征选择与回归分类实战

简介:本资源为2021年华为杯数学建模竞赛D题「抗乳腺癌候选药物优化建模」的完整解答包,面向参加数学建模竞赛的高校学生及对生物信息学、医疗数据分析感兴趣的进阶学习者。内容围绕特征选择、回归预测、二分类建模、最优化求解、模型训练与验证、数据预处… · 2026/9/26 22:40:39

2026年AI写作辅助网站推荐:9款精选AI工具实用宝典(TaoToken统一Key接入版)
2026年AI写作辅助网站推荐:9款精选AI工具实用宝典(TaoToken统一Key接入版)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 22:40:39

做网站需要记哪些代码:告别拖延,掌握这5个核心片段才是最佳实践
做网站需要记哪些代码:告别拖延,掌握这5个核心片段才是最佳实践

做网站需要记哪些代码:告别拖延,掌握这5个核心片段才是最佳实践 改个需求建站公司拖一周,这种痛感谁懂?客户急得跳脚,开发说“逻辑要梳理”,设计说“风格要统一”,最后交付个半成品。其实,很多时候不是技术有多复杂,而是缺乏一套可复用的… · 2026/9/26 22:40:20

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码