我给自己的 Django 博客做了一个在线工具箱:从图片压缩到正则测试,尽量都在浏览器本地处理

我给自己的 Django 博客做了一个在线工具箱:从图片压缩到正则测试,尽量都在浏览器本地处理

这篇文章记录一下我最近给个人博客做在线工具箱的过程。重点不是炫功能,而是整理一下为什么要做、哪些工具适合纯前端实现、Django 后端负责什么,以及实现过程中遇到的一些取舍。

工具箱地址:

https://leedu.ac.cn/tools/

如果你也在做个人博客、技术站点或工具站,这篇文章可以作为一个比较轻量的实现参考。

一、为什么要在博客里做一个工具箱?

平时写文章、做网站、调接口、排查问题时,我经常会临时搜索一些小工具,比如:

  • 图片压缩;
  • 图片格式转换;
  • 二维码生成;
  • JSON 格式化;
  • 时间戳转换;
  • URL 编码解码;
  • Base64 编码解码;
  • 哈希生成;
  • JWT 解码;
  • 正则表达式测试;
  • Favicon 生成;
  • SEO 标题长度检测;
  • ChatGPT、Claude 订阅价格对比。

这些工具单独搜索当然都能找到,但是经常会遇到几个问题:

  1. 页面广告比较多,真正的操作区域不明显;
  2. 有些工具需要把文件上传到服务器;
  3. 临时处理一个小任务,却要反复搜索不同的网站;
  4. 工具之间风格不统一,使用体验比较割裂;
  5. 对 JSON、JWT、2FA 密钥、日志文本这类内容,上传服务器会有隐私顾虑。

所以我最后决定在自己的博客里做一个工具箱,把常用的小工具集中到一个页面里,同时也能增加google收录。

我的目标很简单:

打开就能用,功能直接,尽量在浏览器本地完成处理。

这类工具不一定要做得特别复杂,但必须稳定、清楚、可维护。

二、整体设计思路

我这个博客本身是 Django 项目,所以工具箱没有单独拆一个前端项目,而是直接放进现有博客系统里。

整体职责划分如下:

模块 负责内容
Django URL 每个工具页的路由
Django View 渲染工具页模板
Template 页面结构、SEO meta、结构化数据
Static JS 每个工具的核心前端逻辑
Static CSS 工具页统一样式
Sitemap 让搜索引擎发现工具页
统计模块 记录各工具页打开次数

也就是说,后端主要负责"页面"和"站点能力",真正的数据处理尽量放在浏览器端完成。

这种方式的好处是:

  • 不需要为每个小工具单独写 API;
  • 静态 JS 文件比较容易缓存;
  • 大部分工具不消耗服务器计算资源;
  • 用户文件和文本不需要上传;
  • 后续新增工具时,只要按固定模板扩展即可。

三、哪些工具适合纯前端实现?

不是所有工具都适合纯前端,但很多轻量工具其实完全可以在浏览器里完成。

我目前已经做了这些工具:

工具 是否本地处理 主要技术
图片压缩 File API、Image、Canvas
图片格式转换 File API、Canvas、Blob
二维码生成 JavaScript 二维码库、Canvas/SVG
JSON 格式化 JSON.parse、JSON.stringify
时间戳转换 Date API
字数统计 JavaScript 字符串处理
URL 编码解码 encodeURIComponent、URLSearchParams
Base64 编码解码 btoa、atob、FileReader
哈希生成 Web Crypto API
JWT 解码 Base64URL 解码
UUID / 密码生成 crypto.getRandomValues、crypto.randomUUID
正则表达式测试 RegExp
Favicon 生成 File API、Canvas
URL Slug 生成 字符串规范化
2FA TOTP 验证码 Web Crypto、TOTP 算法
ChatGPT、Claude 订阅价格对比 部分是 本站定期维护数据,前端筛选展示

其中图片、JSON、JWT、2FA、日志文本这类内容,我会特别强调本地处理,因为它们可能包含隐私信息。

四、项目里的页面组织方式

每个工具基本都对应一个独立页面,例如:

text 复制代码
/tools/image-compressor/
/tools/image-converter/
/tools/qr-code-generator/
/tools/json-formatter/
/tools/timestamp-converter/
/tools/regex-tester/
/tools/favicon-generator/
/tools/slug-generator/

Django 路由大致是这种形式:

python 复制代码
urlpatterns = [
    path("tools/", tools_index, name="tools_index"),
    path("tools/image-compressor/", image_compressor, name="image_compressor"),
    path("tools/json-formatter/", json_formatter, name="json_formatter"),
    path("tools/regex-tester/", regex_tester, name="regex_tester"),
    path("tools/favicon-generator/", favicon_generator, name="favicon_generator"),
    path("tools/slug-generator/", slug_generator, name="slug_generator"),
]

View 层尽量保持轻量:

python 复制代码
def regex_tester(request):
    """正则表达式测试器"""
    return render(request, "blog/tools/regex_tester.html")

工具页模板里主要放:

  • title;
  • meta description;
  • canonical;
  • Open Graph;
  • SoftwareApplication 结构化数据;
  • 工具页面 HTML;
  • 对应 JS 文件。

这样每个工具页既是一个可用页面,也是一篇可以被搜索引擎收录的独立页面。

五、核心实现示例

下面放几个比较典型的实现片段。

1. 图片压缩和格式转换:File API + Canvas

图片类工具的基本流程是:

  1. 用户选择本地图片;
  2. 使用 File API 读取文件;
  3. 创建 Image 对象;
  4. 绘制到 Canvas;
  5. 通过 Canvas 导出压缩后的 Blob;
  6. 生成下载链接。

核心思路类似这样:

js 复制代码
const file = input.files[0];
const imageUrl = URL.createObjectURL(file);
const image = new Image();

image.onload = () => {
  const canvas = document.createElement("canvas");
  const context = canvas.getContext("2d");

  canvas.width = image.naturalWidth;
  canvas.height = image.naturalHeight;
  context.drawImage(image, 0, 0);

  canvas.toBlob(
    (blob) => {
      const downloadUrl = URL.createObjectURL(blob);
      // 使用 downloadUrl 生成下载按钮
    },
    "image/webp",
    0.8
  );
};

image.src = imageUrl;

这个方案适合做:

  • JPG 压缩;
  • PNG 转 WebP;
  • WebP 转 PNG;
  • 生成不同尺寸的网站图标;
  • 图片转 Base64。

需要注意的是,特别大的图片会受浏览器内存和设备性能影响,所以前端工具要做好错误提示。

2. 哈希生成:Web Crypto API

文本哈希和文件哈希可以使用浏览器原生的 Web Crypto API。

例如计算 SHA-256:

js 复制代码
async function digestText(text) {
  const encoder = new TextEncoder();
  const data = encoder.encode(text);
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);

  return Array.from(new Uint8Array(hashBuffer))
    .map((byte) => byte.toString(16).padStart(2, "0"))
    .join("");
}

这个能力适合做:

  • 文本 SHA-256;
  • 文件 SHA-256;
  • SHA-512;
  • 文件完整性校验;
  • 内容指纹生成。

我没有优先做 MD5,原因是 MD5 已经不适合作为安全用途,而且 Web Crypto API 也不原生支持 MD5。工具页首版更适合主推 SHA-256 和 SHA-512。

3. UUID 和随机密码:crypto.getRandomValues

随机值生成不要用 Math.random()

浏览器里可以使用 crypto.getRandomValues()

js 复制代码
function randomInt(max) {
  const array = new Uint32Array(1);
  crypto.getRandomValues(array);
  return array[0] % max;
}

function randomString(length, charset) {
  let value = "";
  for (let index = 0; index < length; index += 1) {
    value += charset[randomInt(charset.length)];
  }
  return value;
}

如果浏览器支持 crypto.randomUUID(),生成 UUID v4 会更简单:

js 复制代码
const id = crypto.randomUUID();

这类工具适合开发测试、接口调试和临时生成随机值。

4. 正则表达式测试:RegExp + DOM 安全高亮

正则测试工具需要注意一点:不要把用户输入的文本直接拼成 HTML。

更安全的做法是用 DOM API 创建文本节点和 mark 节点:

js 复制代码
const fragment = document.createDocumentFragment();

fragment.append(document.createTextNode(text.slice(0, match.index)));

const mark = document.createElement("mark");
mark.textContent = match[0];
fragment.append(mark);

highlightOutput.replaceChildren(fragment);

这样可以避免用户输入中包含 HTML 时被当成页面结构执行。

六、为什么每个工具都做独立页面?

一开始我也考虑过做成一个大页面,所有工具都放进去。

但后来还是选择了"工具首页 + 独立工具页"的结构。

原因有几个:

  1. 每个工具可以有独立 URL;
  2. 每个页面可以写更准确的 title 和 description;
  3. 更适合搜索引擎收录长尾关键词;
  4. 页面加载更轻,不需要一次性加载所有工具 JS;
  5. 后台统计时可以看到每个工具的访问量;
  6. 用户分享某个工具时更直接。

例如:

text 复制代码
/tools/regex-tester/
/tools/favicon-generator/
/tools/json-formatter/

这些页面的搜索意图都不一样,拆开之后更清楚。

七、SEO 上做了哪些处理?

因为这个工具箱是放在博客里的,所以我也顺手做了一些 SEO 基础处理。

每个工具页都有:

  • 唯一 title;
  • 唯一 meta description;
  • canonical;
  • Open Graph 信息;
  • sitemap 收录;
  • 页面说明和常见问题;
  • SoftwareApplication 结构化数据;
  • 工具首页入口;
  • 站内导航高亮。

以一个工具页为例,标题会尽量写成用户可能搜索的方式:

text 复制代码
在线正则表达式测试器 - Regex 匹配、分组与替换预览

而不是只写:

text 复制代码
正则工具

这样做的好处是页面主题更明确,也更适合长尾搜索。

八、后台统计怎么处理?

我还给工具页面接了一个简单的访问统计。

主要是为了知道:

  • 哪些工具有人用;
  • 哪些工具几乎没人打开;
  • 后续应该优先优化哪个工具;
  • 哪些页面适合继续写配套文章。

统计粒度不是特别复杂,目前只需要记录每天每个工具页的打开次数。

大致字段类似:

text 复制代码
stat_date
tool_key
tool_name
page_views

这样后台就可以看到每个工具页面的日访问情况。

九、实现过程中踩到的一些细节

1. 静态文件一定要确认部署流程

工具页新增 JS 和 CSS 后,本地能看到效果,不代表服务器也一定正常。

Django 项目部署时要确认:

  • 应用内 static 文件是否提交;
  • 服务器是否执行 collectstatic;
  • Nginx 是否正确服务 staticfiles;
  • 浏览器缓存是否需要刷新。

如果只提交了模板,没有提交静态文件,线上页面就可能没有样式或没有交互。

2. 本地处理也要写清楚边界

"本地处理"不是万能的。

比如:

  • 超大图片可能导致浏览器卡顿;
  • 老浏览器可能不支持部分 API;
  • TOTP 工具不适合长期保存密钥;
  • JWT 解码不等于验签;
  • 正则表达式写得太复杂可能造成性能问题。

这些边界最好在页面里写清楚,避免用户误解工具能力。

3. 不要为了 SEO 堆一堆重复页面

工具页确实适合做长尾关键词,但不能简单复制页面。

比如这些页面看起来都像二维码工具:

text 复制代码
/tools/qr-code-generator/
/tools/url-to-qr-code/
/tools/wifi-qr-code/

如果每个页面内容都高度重复,反而不一定好。

更稳妥的方式是先做好一个功能完整的二维码生成器,再根据真实搜索需求拆细分页面。

十、目前工具箱清单

截至目前,我的工具箱里主要有这些工具:

分类 工具
图片处理 图片压缩、图片格式转换、Favicon 生成
编码转换 Base64、URL 编码解码
开发调试 JSON 格式化、时间戳转换、JWT 解码、哈希生成、正则测试
随机生成 UUID、随机字符串、密码生成
SEO 写作 字数统计、Google SERP 预览、URL Slug 生成
二维码 文本、URL、WiFi、邮箱、电话、vCard 二维码
安全验证 2FA TOTP 验证码生成
价格参考 ChatGPT、Claude 各区订阅价格对比

工具箱地址:

https://leedu.ac.cn/tools/

ChatGPT、Claude 各区订阅价格对比:

图片压缩处理:

十一、后续还准备补哪些工具?

后面我准备继续补一些和开发、SEO、内容创作相关的小工具。

计划中的工具包括:

  • Markdown 转 HTML;
  • Open Graph 预览;
  • FAQ Schema 生成器;
  • robots.txt 生成器;
  • Nginx rewrite 辅助工具;
  • 颜色转换工具;
  • CSS 阴影生成器;
  • HTTP 状态码查询;
  • Cron 表达式解析;
  • User-Agent 解析。

优先级会根据两个因素决定:

  1. 我自己是否高频使用;
  2. 这个工具是否适合通过搜索带来长尾流量。

十二、总结

这次做在线工具箱,我最大的感受是:

小工具本身不一定复杂,但要做成一个长期可维护的工具集合,需要考虑很多细节。

包括:

  • 页面结构;
  • 工具入口;
  • SEO meta;
  • sitemap;
  • 移动端体验;
  • 静态资源部署;
  • 本地处理边界;
  • 后台访问统计;
  • 后续扩展方式。

如果只是做一个临时 Demo,可能一个 HTML 文件就够了。

但如果想把它放进自己的博客或网站里长期维护,我更推荐从一开始就把路由、模板、静态资源、SEO 和统计这些基础能力整理好。

这样后面每新增一个工具,就不是从零开始,而是在已有框架里继续扩展。

相关推荐
geovindu1 小时前
python: Generators Pattern
开发语言·python·设计模式·生成器模式
没有不重的名么1 小时前
spyder使用教程
开发语言·python
Wonderful U1 小时前
Python+Django实战|线上问卷与投票调研系统:自定义题型、问卷发布、链接分享、答卷收集、数据可视化、报表导出
python·信息可视化·django
码不停蹄的玄黓1 小时前
SpringBoot 实现拦截器
java·spring boot·后端
IT_陈寒1 小时前
Java的ArrayList扩容把我坑惨了,原来是这样搞的
前端·人工智能·后端
Cloud_Shy6181 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 36 - 39)
开发语言·人工智能·笔记·python
zmzb01031 小时前
Python课后习题训练记录Day128
开发语言·python
AIFQuant1 小时前
全球行情自动更新、多品种展示、性能优化实战指南
python·性能优化·金融·node.js·restful
蜂蜜黄油呀土豆1 小时前
ReWOO 与 Plan-and-Execute:解耦的规划
python·ai·大模型