别再纠结CSR和SSR了!用Node.js + jsdom手撸一个服务端渲染的猫咪图站(附完整代码) 用Node.js jsdom打造服务端渲染的猫咪图站从理论到实战每次打开一个网页你有没有想过这些图片和文字是怎么出现在你面前的对于开发者来说理解页面渲染的底层原理至关重要。今天我们就来动手实现一个服务端渲染(SSR)的猫咪图片展示站用最直观的方式理解SSR与CSR的区别。这个项目特别适合已经掌握Node.js基础想深入理解现代Web渲染原理的开发者。我们将使用jsdom这个神奇的库它能在Node.js环境中模拟浏览器环境让我们可以在服务端完成传统上只能在浏览器中进行的DOM操作。1. 项目准备与环境搭建在开始编码前我们需要明确几个关键概念。服务端渲染(SSR)意味着HTML内容在服务器上就已经生成完成客户端收到的是可以直接展示的完整页面。与之相对的客户端渲染(CSR)则是服务器只提供基本HTML框架真正的页面内容由浏览器中的JavaScript动态生成。首先创建项目目录并初始化mkdir cat-ssr-demo cd cat-ssr-demo npm init -y npm install jsdom node-fetch这里我们安装了两个关键依赖jsdom模拟浏览器环境的Node.js库node-fetchNode.js版的fetch API用于获取远程数据创建一个基础项目结构/cat-ssr-demo ├── /src │ ├── server.js # 主服务文件 │ └── template.html # HTML模板 ├── /public # 生成的静态文件 └── package.json2. 核心实现用jsdom模拟浏览器环境jsdom的神奇之处在于它能在Node.js环境中完整模拟浏览器环境。让我们看看如何利用它来实现SSRconst fs require(fs); const { JSDOM } require(jsdom); const fetch require(node-fetch); async function generateCatPage() { // 1. 创建模拟的DOM环境 const dom new JSDOM(!DOCTYPE html html head title猫咪图站/title style .cat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; padding: 20px; } .cat-img { width: 100%; height: 200px; object-fit: cover; border-radius: 8px; } /style /head body h1可爱猫咪合集/h1 div idapp classcat-grid/div /body /html); const { document } dom.window; // 2. 获取猫咪图片数据 const response await fetch(https://api.thecatapi.com/v1/images/search?limit9); const cats await response.json(); // 3. 动态构建DOM const app document.getElementById(app); cats.forEach(cat { const img document.createElement(img); img.src cat.url; img.alt 可爱猫咪; img.className cat-img; app.appendChild(img); }); // 4. 生成静态HTML文件 fs.writeFileSync(./public/index.html, dom.serialize()); console.log(SSR页面生成完成); } generateCatPage();这段代码做了几件关键事情创建了一个完整的HTML文档结构从猫咪API获取了9张猫咪图片的数据动态创建img元素并插入到DOM中将最终生成的HTML保存为静态文件3. SSR与CSR的深度对比理解这两种渲染方式的区别对选择合适的技术方案至关重要。让我们通过一个对比表格来直观展示特性SSR (服务端渲染)CSR (客户端渲染)首次加载速度快 - 返回完整HTML慢 - 需要下载JS后再渲染SEO友好度高 - 爬虫直接获取完整内容低 - 初始HTML内容少服务器负载高 - 每次请求都需要渲染低 - 静态文件托管即可交互体验页面切换需要整页刷新局部更新体验流畅开发复杂度需要考虑服务端兼容性只需关注浏览器环境适用场景内容型网站(新闻、博客)交互型应用(后台管理系统)在实际项目中我们经常会采用混合模式(SSRCSR)比如首屏使用SSR保证加载速度和SEO后续交互采用CSR提升用户体验Next.js和Nuxt.js等框架就是基于这种理念4. 项目优化与扩展基础功能完成后我们可以考虑以下几个优化方向4.1 添加页面缓存频繁调用API会拖慢响应速度我们可以添加简单的缓存机制let cachedCats null; let lastFetchTime 0; async function getCatData() { const now Date.now(); // 缓存1小时 if (!cachedCats || now - lastFetchTime 3600000) { const response await fetch(https://api.thecatapi.com/v1/images/search?limit9); cachedCats await response.json(); lastFetchTime now; } return cachedCats; }4.2 支持分页加载扩展我们的API调用支持分页参数async function generateCatPage(page 1) { // ... const response await fetch( https://api.thecatapi.com/v1/images/search?limit9page${page} ); // ... // 添加分页导航 const pagination document.createElement(div); pagination.className pagination; for (let i 1; i 3; i) { const link document.createElement(a); link.href /page-${i}.html; link.textContent i; if (i page) link.className active; pagination.appendChild(link); } document.body.appendChild(pagination); }4.3 添加响应式设计通过媒体查询确保在不同设备上都有良好显示style .cat-grid { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); } media (max-width: 768px) { .cat-grid { grid-template-columns: 1fr; } } /style5. 部署与实战建议完成开发后部署这个SSR应用非常简单因为最终生成的是静态HTML文件。你可以直接托管在GitHub Pages、Netlify或Vercel等静态托管服务上使用Node.js服务器动态生成适合需要实时数据的场景const http require(http); const server http.createServer(async (req, res) { if (req.url /) { await generateCatPage(); const html fs.readFileSync(./public/index.html); res.writeHead(200, { Content-Type: text/html }); res.end(html); } }); server.listen(3000, () { console.log(Server running at http://localhost:3000); });在实际项目中还需要考虑以下因素错误处理API请求失败时的回退方案加载状态在生成页面时显示加载指示器渐进增强确保JS禁用时基础功能仍可用这个项目虽然简单但涵盖了SSR的核心概念。通过动手实践你应该对服务端渲染有了更直观的理解。下次当你使用Next.js或Nuxt.js时就会更清楚它们底层是如何工作的了。