新闻详情

新闻详情

首页 / 资讯中心 / 详情

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

发布时间:2026/9/26 2:25:25来源:尧图网络
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 参数。有问题欢迎评论区交流。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

微信在线AI客服系统全解析:PHP+大模型API落地实战 2026/9/26 3:02:11

微信在线AI客服系统全解析:PHP+大模型API落地实战

简介:一套基于PHP开发的微信在线AI客服系统源码,面向需要快速搭建724小时智能客服平台的中小企业、开发者与运维人员。系统原生对接企业微信,既能进行文本对话、图片分析和视频分析,也内置对话管理、人工转接、咨询提醒等功能&…

阅读更多 →
智能图像分析与目标检测系统构建实战:卷积神经网络与边缘部署 2026/9/26 3:02:04

智能图像分析与目标检测系统构建实战:卷积神经网络与边缘部署

简介:面向计算机视觉开发者与深度学习初学者的智能图像分析与目标检测系统资源包,覆盖从卷积神经网络建模、数据增强、模型优化到迁移学习、边缘计算及多模态融合的完整技术链路,适合用于智能监控、自动驾驶等场景的视觉识别原型搭建。压缩包…

阅读更多 →
Atlas 300V 24G昇腾推理卡部署YOLO全流程实战与避坑指南 2026/9/26 3:01:58

Atlas 300V 24G昇腾推理卡部署YOLO全流程实战与避坑指南

我一开始拿到手里那张贴着 Atlas 标签的 PCIe 卡时,说实话第一反应是:这应该就是一块“24G 显存的运算加速卡”,插上去装个驱动就能当 CUDA 卡用。结果就是这块 Atlas 300V 24G,让我整整折腾了一个多星期。后来回头想,…

阅读更多 →
Bangumi 追番记录 App 发布流程指南:3 步完成 Android 与 iOS 双端打包上架 2026/9/26 3:01:58

Bangumi 追番记录 App 发布流程指南:3 步完成 Android 与 iOS 双端打包上架

Bangumi 追番记录 App 发布流程指南:3 步完成 Android 与 iOS 双端打包上架 【免费下载链接】Bangumi :electron: An unofficial https://bgm.tv ui first app client for Android and iOS, built with React Native. 一个无广告、以爱好为驱动、不以盈利为目的、专门做 ACG 的…

阅读更多 →
Git 实用场景实战指南:从入门到团队协作 2026/9/26 3:01:51

Git 实用场景实战指南:从入门到团队协作

1. 引言 Git 是现代软件开发中不可或缺的版本控制工具,无论是个人开发者还是大型团队,都离不开它。然而,很多初学者面对 Git 时,往往被各种命令和概念搞得一头雾水。本文不打算罗列枯燥的命令手册,而是从实用场景出发&…

阅读更多 →
SolidWorks 2026专业级安装配置指南:许可、驱动与系统优化 2026/9/26 3:01:51

SolidWorks 2026专业级安装配置指南:许可、驱动与系统优化

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉