前后端存储深度解析:Node.js 实现静态资源服务与缓存优化

33 阅读4分钟

在现代 Web 开发中,存储 无处不在:
前端需要在浏览器里存储数据,后端需要把数据长期保存,客户端和服务端之间还要通过网络把数据安全、高效地传输。

这篇文章就结合一个最简单的 Node.js 原生 HTTP 服务器示例,带你串一遍前后端常用的存储方案、模块化演进、端口与路由等核心知识点,顺便看看底层是怎么跑起来的。

📦 1. 前端存储:从 Cookie 到 IndexDB

1.1 Cookie

Cookie 是最老牌的浏览器存储方案,浏览器会在每次请求时自动带上它。常见用途:

  • 登录状态:比如存 session ID 或 token,让后端识别用户身份。
  • 购物车信息:如果网站没有登录功能,也可以先把购物车信息放在 Cookie 中。

特点:

  • 每次请求都会带上,体积要尽量小(限制 4KB)。
  • 有过期时间和作用域。

1.2 localStorage 与 sessionStorage

这俩是更现代的浏览器存储方案,都不会随请求自动发送,纯本地保存。

  • localStorage:持久化存储,除非用户主动清理,否则一直存在。
  • sessionStorage:生命周期只在当前标签页或窗口内,有效期更短。

简单用法:

localStorage.setItem('key', 'value');
const val = localStorage.getItem('key');

1.3 IndexDB

当需要在浏览器里存储更大、结构化的数据时,IndexDB 更合适。
它支持事务、索引查询和异步操作,常用于离线应用、缓存大文件或前端搜索等场景。


🗄️ 2. 后端存储:从关系型到非关系型

后端要处理持久化、事务、并发和可扩展性,常见选型包括:

  • MySQL:典型的关系型数据库,表结构清晰,事务支持好,适合对一致性要求高的场景。
  • NoSQL:如 MongoDB(文档型)、Redis(键值对),读写性能高,适合存非结构化或高并发的热点数据。

例如:用户表、订单表通常放 MySQL;缓存、Session 可以放 Redis。


⚡ 3. 缓存

缓存无处不在:

  • 前端:浏览器自带的强缓存、协商缓存,或者 Service Worker 做离线缓存。
  • 后端:Redis、Memcached 等把热点数据放内存,减少数据库压力。

合理使用缓存能极大提高网站的访问速度和并发能力。


🧩 4. Node.js 的模块化与原生 HTTP 服务实践

4.1 模块化

JavaScript 的模块化方案主要有两种:

  1. CommonJS(require) :Node.js 早期标准,语法简单,使用广泛。

    const http = require('http');
    
  2. ES6 Module(import) :ECMAScript 标准,自带模块化能力,支持更好的静态分析和 Tree Shaking。

    import http from 'http';
    

    Node.js 从 12 版本后就逐步支持了 ES6 模块化(通过 .mjs 后缀或在 package.json 中声明 "type": "module")。
    社区也在逐步从 require 迁移到 importrequire 未来可能会淡出。


4.2 原生 HTTP 服务示例 + 详细解析

下面是一份最小可用的 Node.js 原生 HTTP 静态资源服务器示例,包含路由、读文件、正确设置响应头等关键点。


📄 完整示例

const http = require('http');
const fs = require('fs'); // 文件操作模块
const path = require('path'); // 路径操作模块

const server = http.createServer((req, res) => {
  // 根据请求 Method + URL 路由
  if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) {
    fs.readFile(path.join(__dirname, 'public', 'index.html'), (err, content) => {
      if (err) {
        res.writeHead(500);
        res.end('Server error');
        return;
      }
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content);
    });
  } else if (req.method === 'GET' && req.url === '/style.css') {
    fs.readFile(path.join(__dirname, 'public', 'style.css'), (err, content) => {
      if (err) {
        res.writeHead(500);
        res.end('Server error');
        return;
      }
      res.writeHead(200, { 'Content-Type': 'text/css' });
      res.end(content);
    });
  } else if (req.method === 'GET' && req.url === '/script.js') {
    fs.readFile(path.join(__dirname, 'public', 'script.js'), (err, content) => {
      if (err) {
        res.writeHead(500);
        res.end('Server error');
        return;
      }
      res.writeHead(200, { 'Content-Type': 'text/javascript' });
      res.end(content);
    });
  } else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

server.listen(8080, () => {
  console.log('Server is running on http://localhost:8080');
});

✅ 逐步解析

1) 核心模块

  • http:创建服务器
  • fs:读取静态文件
  • path:拼接路径,保证跨平台兼容

2) 创建服务

const server = http.createServer((req, res) => {
  // 每次请求都会进入这个回调
});
  • req:请求信息(方法、路径、头信息)
  • res:响应对象,用来返回数据

3) 路由匹配

  • GET //index.html:读取并返回首页 HTML
  • GET /style.css:读取并返回 CSS
  • GET /script.js:读取并返回 JS
  • 其他:404

每个路由都做了:

  • fs.readFile 异步读取文件内容
  • 设置合适的 Content-Type
  • 错误处理:如果文件读不到返回 500,找不到路由返回 404

4) 响应头的作用

Content-Type 决定浏览器如何解析返回的文件:

  • HTML:text/html
  • CSS:text/css
  • JS:text/javascript

如果少了或写错了,浏览器可能当成纯文本处理,页面就会显示异常。


5) 启动服务器

server.listen(8080, () => {
  console.log('Server is running on http://localhost:8080');
});
  • 8080 是常见的开发环境端口,避免跟常用服务(如 80/3306/6379)冲突。
  • localhost 会解析成 127.0.0.1,只在本机可访问。

🌐 4.3 前端示例文件

public 目录下,放上简单的前端文件:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Storage</title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <h1>Cookie</h1>
  <script src="/script.js"></script>
</body>
</html>
/* public/style.css */
* {
  margin: 0;
  padding: 0;
}
body {
  background-color: green;
  height: 100vh;
}
// public/script.js
console.log('智能前端,智能后端,笑傲秋招');

🌍 5. 域名、IP 和端口

顺带复习下基础概念:

  • 域名(如 localhost) :解析成 IP(如 127.0.0.1)
  • 端口(如 8080) :同一台机器上的不同服务/进程通过不同端口区分
  • 访问 URL 完整结构:http://域名:端口/路径?查询参数

这些都是前端与后端打交道时必备的底层知识,理解了这些,写更复杂的全栈应用、面试原理题都会轻松很多。