网站「优如化」和「防如护」踩坑指北
之前一直在搜索相关资料、以进一步优化本站的性能并提升本站的防护,但网络上做「优化」和「防护」的缘由算是众说纷纭、一个比一个离谱。因此,这篇文章我将瞎写一通、抛开一切杂七杂八的、过多考虑无任何意义的外部因素、回归到本质问题,以「网站优化」和「网站防护」两个方面出发,分享一路上如何精准进行一个踩坑。
优化篇
《灵魂拷问 I》:网站样式真需要如此华丽?
曾经出于找资料需求访问过 N 个网站,而这些网站中有那么一部分特别亮眼:精美的样式、华丽的动效、呆萌的标题(指切换到别的标签页)、可爱的指针,以及可爱的 Live2D 看板娘......
所以这就是我用十几秒打开这个网站、浏览还一卡一卡的理由?!
网络上对这类网站的评价不怎么好,这些声音里有冷静概述的、也有直接「炮轰」的。把话说得好听一点:我确实可以理解部分站长有爱美之心。但追求「美」的同时,一定不要把「美」所带来的副作用抛给用户买单。
《灵魂拷问 II》:优化插件一定能优化吗🤔
有过 WordPress 网站站长加了 N 多个插件「优化」网站,但其中一部分插件在实际上并无多大作用、甚至开倒车。
适当使用 CDN
CDN 确实有助于提升网站的访问体验。但是,如果将优化的所有希望寄托于 CDN、其它优化方面未能尽善,未必能体现出 CDN 的优势。
你可能不需要 CSR 或 SSR
猜一手:正在阅读本文的你是一个博主。
再猜一手,你的网站是 {packageManager} create vite 然后直接搭建起来的,且构建指令是 vite build。那么恭喜你:你的博客实质上是在访客的浏览器上完成渲染的。在完成渲染之前,他们只会看到一片空白。
在没有对构建步骤做额外处理的情况下,你默认创建的是一个 Vite SPA 应用。这里涉及到 SPA 的渲染方式:CSR(Client-Side Rendering,即客户端渲染),它的诞生是为了降低 SSR(Server-Side Rendering,即服务端渲染)为服务器带来的压力,但问题也随着时间推移而逐渐展现:
-
客户端渲染,顾名思义就是在客户端上渲染网站内容,如同上文讲述的一样:在浏览器下载完成并执行 JavaScript 前,访客看不到任何内容;
-
一些低级的爬虫无法处理 CSR,因此它们并不知道你的网站上有什么内容。
这或许也是 SSR 重新受到青睐的缘由。不过,SSR 虽然能完美解决 CSR 的痛点,但它的弊端在上文也讲了:会为服务器带来一定的压力。假设你的 SSR 网站托管在类似 Cloudflare Workers, Vercel 这样的 Serverless Platform,这个问题会更加明显。
正解是使用 SSG(Static-Site Generation,即静态站点生成),因为博客的内容并非经常变动、只需要渲染一次即可,如有变更就再次重新渲染。这里的 SSG 和 Hexo 这类静态网站生成器不同,它算是一次性的 SSR:在 Vite 构建完服务端产物后,通过一系列的步骤将这些产物转换为实际的 HTML 文件。如此,构建产物仅仅只有 HTML, CSS 和 JavaScript,你可以直接将它部署在任何静态网站托管上。
Vite 文档给出了 SSG 代码示例。对于 Vue 用户,可以考虑使用 Anthony Fu 制作的 vite-ssg,仅需按 README 上的步骤修改入口文件(main.ts)和构建指令(vite build 修改为 vite-ssg build),即可快速享受到 SSG 带来的好处。
这里是我在 2024 年帮助 Bailey's Blog 从 SPA 应用迁移至 SSG 的一个 Pull Request。
CSS 还能更小
像 TailwindCSS, UnoCSS, StyleX, Panda CSS 和 Vanilla Extract 这样的 CSS 工具问世之前,(或许是大部分的)网站样式基本是这么写的:
.class1 {
display: flex;
justify-content: space-between;
}
.class2 {
display: flex;
justify-content: center;
}
...然后再以 <div class="class1"></div> 这样的形式,将 CSS 应用在元素上。CSS 选择器这里不详提。
在网站的样式实现中,不可避免地会用到同一条 CSS 规则,如同上面的例子中、class1 和 class2 都重复声明了 display: flex 这一条规则。长久以往会导致 CSS 体积膨胀,Gzip 来了都不一定救得了。
正是在这种状况下,基于 Utility-First CSS 概念的 Tailwind CSS 逐渐受到社区关注:它将 CSS 进行了功能划分,每一个功能类名对应相应的 CSS 规则。并且,功能越简单,可复用率越高,相比重复声明能有效缩小 CSS 的体积。
但是,Tailwind CSS 主动帮我们命名好了各个功能 CSS 的类名。大部分的功能类名确实挺短,但少部分的类名会拖得很长,并且用户没法自己修改。这一点由后来的、由 Anthony Fu 制作的 UnoCSS 解决,且 UnoCSS 可以踏入到 Utility-First CSS 的极致抽象领域:Atomic CSS,即一个类名仅仅只对应一条 CSS 规则。
但很明显,就算用了 UnoCSS,使用 Tailwind 预设仅仅只带来 UnoCSS 相较于 Tailwind CSS 的提升,使用社区的 CSS 规则集又不太适应,自己写规则集又麻烦,因此我选用了 Atomic CSS-in-JS 方案。这个方案相较于 Atomic CSS 带来了很多优势,但对我而言,我可以让其生成 hash classname,以保证 CSS 类名不会那么的长。
本站使用了 Panda CSS,我的个人主页使用了 StyleX。
在使用 Panda CSS 编写网站样式后,构建后 CSS 未压缩体积为 6KiB,压缩后仅有 3KiB。
不要导入所有的图标
在很久以前,许多使用 Font Awesome 的网站通过引入一个 CSS 文件来加载图标,而这个 CSS 文件包含了所有可用的图标、不论你是否用得上。导入图标库里的所有图标、却只用到其中那寥寥几个,实属不值。
我的做法是:在 Icônes 先寻找到需要的图标、复制 SVG 代码并粘贴到 HTML 模板中。如果你是 UnoCSS 用户,也可以使用它的 Icons preset 来实现。
图片能压缩则压缩
有一些网站的配图采用了原始图像。一方面,插入的图片分辨率可能小(甚至远小)于图像本身的分辨率;另一方面,随高分辨率而来的便是成倍的文件体积,最终以「加载时长」和「流量消耗」这两个角度让用户买单。
Google Chrome Labs 做了一个名为 Squoosh 的项目,用于压缩图片质量、减小文件体积,并转换图像文件的格式。我一般用它将本站插入的图片压缩为 75% 质量的 WebP 图像。
防护篇
如果你的网站和我一样、静态渲染且部署在 Cloudflare 上,那其实你可以不用继续往下看了。本部分会涉及到传统的「服务器部署」以及「WAF」的相关内容。
守好你的服务器
部分动态网站的站长将域名直接解析到源服务器上、或是不小心把源服务器 IP 给泄露了。更有部分站长连 SSH 端口都保持着默认的 22,且 服务器仅有最基本的密码认证。
建议的方案如下:
-
套一层边缘防护 CDN,注意是带有边缘防护的、不是普通的内容分发网络,常见的便是
赛博菩萨Cloudflare,国内有 Tencent EdgeOne 但不确定使用效果和体验如何; -
可以不考虑更改 SSH 端口,但登录认证最好 禁用密码、改用 SSH 认证。
别让流量白白跑了
对于普通的 CDN,以及 Vercel、Netlify 这类有流量限制的 Serverless Host,如果不编写恰当的防火墙规则,想刷掉 100GB 流量简直轻轻松松。
善用防火墙规则。
容器化部署
2025 年的最后一个月似乎并不太平:React 被披露存在高危漏洞,该漏洞可以通过伪造 RSC Payload 请求、在服务器上执行任意 JavaScript 代码,无需任何验证、交互,甚至权限提升。这个漏洞导致受到波及、但未能及时升级的 React 项目遭到攻击,部分攻击者甚至加密了被攻击服务器上的数据。
虽然这个问题发生在 React 用户的身上,但 PHP 应用被攻击的案例显然要比前者更丰富。因此强烈建议将网站相关的程序容器化部署,这样即使像上面的例子一样、受到波及但未能及时更新,被波及到的也只有对应的容器、不会影响到整个服务器。