🌈 前端存储与后端服务的奇妙冒险:一个Node.js服务器的诞生记
从前端存储到后端服务,一次完整的Web请求是如何在底层翩翩起舞的?

存储世界的奇妙分层
在Web开发的奇幻世界里,存储分为不同的王国:
🍪 前端存储王国
- Cookie:小小的饼干,记录着用户的登录状态和购物车信息
- localStorage:可靠的本地仓库,能长期保存数据
- sessionStorage:会话专属的临时储物柜
- IndexedDB:强大的前端数据库,能存储结构化数据
🏰 后端存储王国
- MySQL:经典的关系型数据库城堡
- NoSQL:灵活的非关系型数据库王国
- MongoDB:文档型数据库的魔法世界
⚡ 缓存精灵
- 在前后端之间快速穿梭,加速数据传递的使者
Node.js:前后端之间的桥梁
node.js是什么
Node.js 就像一个能让 JavaScript 语言在电脑后台「搞事情」的超级引擎,原本 JavaScript 只能在浏览器里「画画网页、动效」,现在有了它,JavaScript 能直接在电脑里「管文件、开服务器、连数据库」,彻底跳出浏览器限制!
用生活场景秒懂 Node.js
1. 它是「快递中转站」:处理大量请求不卡顿
- 传统服务器像「人工分拣快递」:来一个请求就派一个人专门处理(多线程),人多了会挤爆(内存占用高)。
- Node.js 像「智能传送带」:用「事件循环」单线程处理所有请求,来快递先登记(排队),传送带逐个处理(非阻塞 I/O),哪怕同时来 1000 个快递也不慌,适合处理大量「查快递进度」这种轻任务(I/O 密集型场景)。
2. 它是「前后端的翻译官」
- 前端工程师用 JavaScript 写网页,后端工程师以前得学 Java/Python 写服务器,现在用 Node.js 后,前后端都能用 JavaScript,就像两个人终于能说同一种语言,开发效率翻倍!
核心能力拆解
1. 能在电脑里「开商店」(搭服务器)
-
以前开商店(建网站)需要租门面(买服务器)、雇店员(写后端代码),现在用 Node.js,只要在自己电脑输入几行代码,就能瞬间开个「线上商店」:
javascript// 开店代码(server.js) const http = require('http'); // 相当于「开店工具包」 http.createServer((顾客req, 店员res) => { res.end('欢迎光临,这是你的商品!'); // 给顾客递东西(返回网页内容) }).listen(8080); // 商店开在 8080 号门(端口)
运行后访问
http://localhost:8080
,就能看到商店(服务器)的回应。
2. 能「翻箱倒柜」(操作文件)
-
比如把电脑里的照片批量重命名:
javascriptconst fs = require('fs'); // 文件操作工具 fs.readdir('./照片', (err, files) => { // 读「照片」文件夹 files.forEach(file => { const newName = '美景_' + file; fs.rename(`./照片/${file}`, `./照片/${newName}`, err => { if (!err) console.log(`${file} 已重命名为 ${newName}`); }); }); });
3. 能「打电话」(连数据库、调接口)
-
比如从「用户数据库」里查张三的信息:
javascriptconst mysql = require('mysql'); // 数据库电话本 const connection = mysql.createConnection({ host: '数据库地址', user: '用户名', password: '密码', database: '用户库' }); connection.query('SELECT * FROM 用户 WHERE 姓名 = "张三"', (err, results) => { console.log(results[0].年龄); // 输出张三的年龄 });
为什么它对普通人很重要?
- 你刷的抖音、逛的淘宝,背后可能有 Node.js:比如抖音的直播弹幕系统,需要同时处理百万用户发弹幕,Node.js 的「非阻塞」特性让弹幕不卡顿。
- 你用的手机 APP 背后也可能有它:比如某外卖 APP 的「附近商家」接口,用 Node.js 能快速返回商家列表,不用等很久。
- 你电脑里的「神器工具」很多是它做的:比如「一键压缩图片」的桌面软件、「自动生成 PPT」的小工具,很多都是用 Node.js 开发的。
和浏览器 JavaScript 的区别
场景 | 浏览器 JavaScript(网页里的 JS) | Node.js JavaScript(后台的 JS) |
---|---|---|
能力范围 | 只能在网页里「画画」(改文字颜色、动效)、「问用户问题」(弹对话框) | 能在电脑里「翻文件」「开服务器」「连数据库」,像个全能管家 |
运行位置 | 必须打开网页才运行(在浏览器里) | 直接在电脑后台运行(像 QQ 一样后台运行) |
经典例子 | 点击按钮让图片动起来 | 把电脑里所有图片压缩后发到邮箱 |
总结:Node.js 就是「JavaScript 的超能力扩展包」
它让原本只能在浏览器「玩小游戏」的 JavaScript,变成了能在电脑里「干重活」的全能选手,无论是搭网站、做工具、连数据库,都能用同一门语言搞定,大大降低了开发门槛 ------ 这也是为什么现在很多程序员都爱用它的原因!
模块化的双生子
在JavaScript的世界里,有两种模块化方式:
javascript
// CommonJS 方式 - Node.js的传统方式
const http = require('http');
// ES6 方式 - 现代JavaScript的方式
import http from 'http';
有趣的是,Node.js最初只支持CommonJS,但随着发展,现在也拥抱了ES6模块化。文件后缀的差异:
.js
:默认使用CommonJS.mjs
:明确使用ES6 module(es6模块化)
.js与.mjs区别
特性 | .js (CommonJS) |
.mjs (ES6 Modules) |
---|---|---|
模块语法 | require() 和 module.exports |
import 和 export |
路径要求 | 可省略扩展名(如 ./utils ) |
必须写完整路径(如 ./utils.mjs ) |
顶层 await |
❌ 仅支持在 async 函数中 |
✅ 可直接在模块顶层使用 |
全局变量 | 有 __dirname 、__filename |
无,需通过 import.meta.url 计算 |
JSON 导入 | 直接 require('./data.json') |
需 import data from './data.json' assert { type: 'json' } |
与其他模块互操作 | 可直接 require('.mjs') |
需动态导入:import('./.js').then(...) |
建议使用es6 Module模块化,它支持静态分析(如 Tree-shaking 减小打包体积),前后端语法统一且与现代工具链(TypeScript、Vite)无缝集成,同时提供顶层 await
和动态导入 import()
简化异步逻辑,并且符合 Node.js 向 ES6 模块全面迁移的未来趋势。
端口的秘密通道
1.端口的核心概念
端口(Port)是计算机网络中用于标识不同应用程序或服务的数字标识符,范围从 0 到 65535。它的作用类似于一栋大楼中的 "房间号",当网络请求到达设备(IP 地址)后,系统通过端口号将数据转发给对应的应用程序。
2.为什么需要端口?
-
复用 IP 地址:同一设备(IP)可同时运行多个服务(如 Web 服务器、数据库、邮件服务),通过端口区分。
-
唯一标识服务:每个服务绑定特定端口,确保请求被正确路由。例如:
80
端口默认分配给 HTTP 服务(如 Nginx、Apache)。443
端口用于 HTTPS(加密的 Web 服务)。3306
端口对应 MySQL 数据库服务。
3.域名 → IP → 端口 的详细流程
以 http://localhost:8080
为例:
端口背后对应一个服务,一个服务对应一个进程(资源),进程的背后是线程(执行)
域名domain(localhost) -> ip地址(127.0.0.1) -> -> 某台设备 -> port 设备上的某个服务(进程)
一台设备上可以有很多端口使用,有多个http服务运行多个网站
-
域名解析
localhost
是预定义的本地域名,直接映射到127.0.0.1
(无需 DNS 查询)。 -
网络请求
浏览器向
127.0.0.1:8080
发送 HTTP 请求,数据包包含:- 源地址 :客户端 IP + 临时端口(如
192.168.1.5:56789
)。 - 目标地址 :
127.0.0.1:8080
。
- 源地址 :客户端 IP + 临时端口(如
-
路由与转发
- 数据包通过网络到达本地设备(
127.0.0.1
)。 - 操作系统根据目标端口
8080
,将请求转发给监听该端口的进程(如 Node.js 服务器、Tomcat)。
- 数据包通过网络到达本地设备(
-
服务处理
监听
8080
端口的应用程序接收请求,处理后返回响应,路径反之。
4.注意事项
-
端口占用 :若多个应用尝试绑定同一端口,会导致冲突(如启动两个监听
8080
的服务)。 -
防火墙 :需开放特定端口才能让外部访问(如
80/443
用于 Web 服务器)。 -
安全风险:暴露敏感端口(如数据库端口)可能导致攻击,建议限制访问或使用防火墙。
🌟 Node.js服务器诞生记
让我们跟随这段代码,一起探索一个Node.js服务器(后端)的诞生过程:
javascript
// 引入必要的魔法工具包
const http = require('http'); // 网络通信的魔法书
const fs = require('fs'); // 文件系统的魔杖
const path = require('path'); // 路径导航的罗盘
// 创建服务器:一个待命的服务精灵
const server = http.createServer((req, res) => {
// 请求(req)和响应(res)在这里交流
// 魔法路由:根据请求的路径分派任务
if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) {
// 读取首页的魔法书
console.log('正在寻找魔法书位置:',
__dirname, 'public', 'index.html',
path.join(__dirname, 'public', '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); // 将魔法书内容送回
});
}
// 处理CSS魔法药剂
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);
});
}
// 处理JavaScript魔法咒语
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);
});
}
});
// 服务器在8080港口开始守望
server.listen(8080, () => {
console.log('服务器已在 http://localhost:8080 上启航!🚢');
});
🧙♂️ 魔法解析:代码背后的秘密
1. 核心模块的召唤
这些都是node的内置核心模块,node自带,所以无需额外下载,只需要引入即可
javascript
const http = require('http');
const fs = require('fs');
const path = require('path');
http
:创建HTTP服务器的核心魔法fs
:操作文件系统的魔杖path
:安全处理路径的罗盘
2. 创建服务器:服务精灵的诞生
javascript
const server = http.createServer((req, res) => { ... });
这里诞生了一个服务精灵,它时刻准备着处理请求(req)和发送响应(res)
3. 路由魔法:请求的分派中心
javascript
if (req.method === 'GET' && req.url === '/') { ... }
req.method
:请求的方法(GET、POST等)req.url
:请求的路径(如'/'、'/style.css')


4. 文件读取的魔法
javascript
fs.readFile(path.join(__dirname, 'public', 'index.html'), (err, content) => { ... }
__dirname
:当前魔法书所在的目录path.join()
:安全拼接路径的魔法public
通常代表项目中的静态资源目录,用于存放客户端(浏览器)可直接访问的文件,如 CSS、JavaScript、图片等。- 回调函数:异步魔法的核心,文件读取完成后触发
5. 响应的艺术
javascript
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(content);
writeHead()
:设置响应头和状态码200
:一切正常的魔法信号Content-Type
:告诉浏览器如何处理内容
end()
:结束响应并发送内容
6. 错误处理:魔法的安全网
javascript
if (err) {
res.writeHead(500);
res.end('Server Error');
return;
}
当魔法出错时(如文件不存在),发送500错误信号,保护服务器不崩溃
7. req与res解析
1. 请求对象 req
req
是客户端(如浏览器)发送给服务器的信息,包含三个核心部分:
1.1 请求行(Request Line)
请求的第一行,格式为:METHOD PATH HTTP_VERSION
。
- METHOD :HTTP 方法(如
GET
、POST
、PUT
、DELETE
)。 - PATH :请求的路径(如
/users
、/api/products
)。 - HTTP_VERSION :HTTP 协议版本(如
HTTP/1.1
)。
示例:
http
GET /home HTTP/1.1
1.2 请求头(Request Headers)
紧随请求行后的键值对,包含元数据(如浏览器类型、缓存策略、内容类型等)。
常见请求头:
User-Agent
:客户端信息(如Mozilla/5.0 (Windows NT 10.0)
)。Content-Type
:请求体的格式(如application/json
)。Cookie
:客户端存储的会话信息。Authorization
:认证凭证(如 Token)。
示例:
http
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
Content-Type: application/json
1.3 请求体(Request Body)
可选部分,用于携带数据(如表单提交、JSON 数据)。
-
GET 请求:通常没有请求体。
-
POST/PUT 请求 :常见格式有
application/json
、application/x-www-form-urlencoded
。
示例(JSON 请求体) :
json
{
"username": "john",
"password": "123456"
}
2. 响应对象 res
res
是服务器返回给客户端的信息,同样包含三个核心部分:
2.1 响应行(Status Line)
响应的第一行,格式为:HTTP_VERSION STATUS_CODE STATUS_MESSAGE
。
- HTTP_VERSION :协议版本(如
HTTP/1.1
)。 - STATUS_CODE :状态码(如
200
成功、404
未找到、500
服务器错误)。 - STATUS_MESSAGE :状态描述(如
OK
、Not Found
)。
示例:
http
HTTP/1.1 200 OK
2.2 响应头(Response Headers)
服务器返回的元数据,控制客户端行为(如缓存、内容类型、跨域设置等)。
常见响应头:
Content-Type
:响应体的格式(如text/html
、application/json
)。Cache-Control
:缓存策略(如max-age=3600
)。Set-Cookie
:在客户端设置 Cookie。Access-Control-Allow-Origin
:跨域资源共享(CORS)设置。
示例:
http
Content-Type: application/json
Cache-Control: no-cache
Set-Cookie: session_id=123456
2.3 响应体(Response Body)
服务器返回的实际数据(如 HTML 页面、JSON 数据、图片等)。
示例(JSON 响应体) :
json
{
"success": true,
"data": {
"id": 1,
"name": "Product A"
}
}
Node.js 中的 req
和 res
对象
在 http.createServer
回调中:
req
对象常用属性和方法
req.method
:HTTP 方法(如GET
、POST
)。req.url
:请求路径(如/home
)。req.headers
:请求头对象(如req.headers['content-type']
)。req.on('data', callback)
:监听请求体数据(流式处理)。req.on('end', callback)
:请求体接收完毕的回调。
res
对象常用属性和方法
res.statusCode
:设置状态码(如res.statusCode = 404
)。res.setHeader(name, value)
:设置响应头(如res.setHeader('Content-Type', 'application/json')
)。res.write(data)
:写入响应体数据。res.end()
:结束响应并发送数据(可选参数:res.end('Hello World')
)。
示例代码:处理请求和响应
javascript
const http = require('http');
const server = http.createServer((req, res) => {
// 1. 解析请求行和请求头
console.log(`请求方法: ${req.method}`);
console.log(`请求路径: ${req.url}`);
console.log(`请求头:`, req.headers);
// 2. 处理请求体(适用于 POST/PUT)
let body = '';
req.on('data', (chunk) => {
body += chunk;
});
req.on('end', () => {
// 3. 设置响应头
res.setHeader('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Origin', '*');
// 4. 设置状态码
res.statusCode = 200;
// 5. 构建响应体
const responseData = {
message: 'Hello from server!',
method: req.method,
path: req.url,
body: body ? JSON.parse(body) : {}
};
// 6. 发送响应
res.end(JSON.stringify(responseData));
});
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
总结
- 请求(
req
) :客户端 → 服务器,包含 请求行(方法 + 路径)、请求头(元数据)、请求体(数据) 。 - 响应(
res
) :服务器 → 客户端,包含 响应行(状态码)、响应头(元数据)、响应体(数据) 。 - Node.js 处理流程:解析请求 → 处理业务逻辑 → 设置响应头和状态码 → 返回响应体。
🌈 前端与后端的存储探戈
当浏览器收到响应后,前端的存储魔法开始发挥作用:
在这个过程中,前端存储扮演着重要角色:
- Cookie:自动随请求发送,用于身份验证
- localStorage:持久保存用户偏好设置
- sessionStorage:临时保存标签页数据
- IndexedDB:存储大量结构化数据
🧠 为什么无状态的http却能够实现有状态的用户登录与会话管理?------Cookie 底层存储机制解析
js
if(req.method == 'POST' && req.url == '/login'){//首页
//用户名和密码的校验
res.writeHead(200,{
//服务器端设置的cookie
'Set-Cookie':"username=admin;",
'Content-Type':"application/json"
})
res.end(JSON.stringify({success:true,mag:"登入成功"}))
}
if(req.method == 'GET' && req.url == '/check-login'){
if(req.headers.cookie){
res.writeHead(200,{
contentType:'application/json'
})
res.end(JSON.stringify({
loggedIn:true,
username:'admin'
}))
}else{
res.writeHead(200,{
contentType:'application/json'
})
res.end(JSON.stringify({
loggedIn:false,
username:''
}))
}
}
1. 服务器设置 Cookie
javascript
// 服务器端设置 Cookie
if(req.method == 'POST' && req.url == '/login'){
res.writeHead(200,{
'Set-Cookie': "username=admin;", // ← 核心设置语句
'Content-Type': "application/json"
})
res.end(JSON.stringify({success:true,msg:"登入成功"}))
}
底层机制:
Set-Cookie
响应头指示浏览器存储指定的 Cookie- 格式为键值对:
username=admin
- 未设置过期时间,默认为会话 Cookie(关闭浏览器即失效)
- 未指定路径,默认为当前路径(
/
)
2. 浏览器自动存储
浏览器收到响应后:
- 解析
Set-Cookie
头部 - 将键值对存储在内存或硬盘中(按域名隔离)
- 存储位置:浏览器 Cookie 存储区
- 最大容量:约 4KB(单个域名下)
3. 自动携带 Cookie
javascript
// 浏览器发起请求时自动携带 Cookie
if(req.method == 'GET' && req.url == '/check-login'){
if(req.headers.cookie){ // ← 浏览器自动注入
// 处理 Cookie 逻辑
}
}
底层机制:
-
浏览器检查当前请求的域名和路径
-
匹配有效的 Cookie(未过期+域名路径匹配)
-
自动添加到请求头的
Cookie
字段:httpGET /check-login HTTP/1.1 Cookie: username=admin // 自动携带
4. 存储位置与结构
浏览器内部存储结构(伪代码表示):
javascript
cookies = {
"localhost:8080": {
"/": [
{
name: "username",
value: "admin",
expires: null, // 会话 Cookie
httpOnly: false,
secure: false
}
]
}
}

5. 完整生命周期
2. 域名隔离存储 Client->>Server: GET /check-login Note left of Client: 自动添加请求头:
Cookie: username=admin Server->>Client: 返回登录状态 Client->>Server: 后续所有请求 Note left of Client: 持续携带Cookie
直到浏览器关闭
6. 安全特性
为避免安全隐患,建议添加:
javascript
// 更安全的Cookie设置
res.writeHead(200,{
'Set-Cookie':
`username=${encodeURIComponent(username)}; ` +
'HttpOnly; ' + // 禁止JS访问
'SameSite=Lax; ' + // 基本跨站防护
'Path=/; ' + // 作用路径
'Max-Age=3600', // 1小时有效期
'Content-Type': "application/json"
})
7. 浏览器开发者工具验证
在Chrome开发者工具中:
- Application > Storage > Cookies 查看存储的Cookie
- Network 标签查看请求/响应头中的Cookie传输
核心原理 :Cookie 通过
Set-Cookie
响应头设置,浏览器自动存储并在后续请求中通过Cookie
请求头发送,实现了 HTTP 无状态协议的身份保持功能。
🚀 开发小贴士:魔法师的工具箱
-
自动重启魔法:
bashnpm install -g nodemon nodemon server.js
让服务器在代码变化时自动重启
-
路径的奥秘:
javascriptconsole.log(path.join('/foo', 'bar', 'baz/asdf', 'quux', '..')); // 输出: '/foo/bar/baz/asdf'
path.join()
会正确处理路径分隔符和..
父目录 -
内容类型的魔法语言:
文件类型 Content-Type HTML text/html CSS text/css JavaScript text/javascript JSON application/json 图片 image/*
🌟 总结:存储与服务的和谐交响
从前端存储到后端服务,我们完成了一次完整的Web魔法之旅:
- 前端存储:在用户浏览器中保存数据的小精灵
- 后端服务:处理请求、读取文件、发送响应的魔法师
- HTTP协议:连接前后端的魔法通信协议

理解这些底层原理,就如同掌握了Web开发的魔法语言。无论是存储用户数据的前端精灵,还是处理请求的后端魔法师,它们共同构建了我们每天使用的互联网世界。
下次当你打开一个网页时,不妨想象一下背后这些奇妙的小精灵们是如何协同工作的!✨