Node.js新手教程:从零开始学习服务器端JavaScript
作者:一个从 Android 跳槽到 Flutter 的跨端搬砖人,日常在 GitHub 上“考古”,偶尔研究点区块链项目自嗨。坐标深圳南山某鹅厂生态公司,最近被产品经理逼着搞了个全栈 demo。
上周五晚上 9 点半,我还在工位上对着 VSCode 发呆,产品经理突然甩过来一句话:“能不能把我们 App 里的用户行为埋点数据实时存下来?下周三演示用。”
我当时就想反问一句:“您知道我们现在连个后端服务都没有吗?”
但嘴上只能笑着说:“可以,我试试。”
其实心里已经在咆哮了:我一个写 Flutter 的,现在要自己搭后端?还要实时存数据?还要下周三上线?
无奈之下,Node.js 成了唯一选择——轻量、JavaScript 全栈、开发快,而且社区轮子多到能造火箭(虽然有时候造的是共享单车)。
为什么是 Node.js?
先说说我这个“前 Android,现 Flutter”的视角。以前写 Java/Kotlin 的时候,搞个 HTTP 接口要配 Spring Boot、Maven、Tomcat……一套流程下来,我都想直接辞职回老家种地。
而 Node.js 不一样,你装个 express,10 行代码就能跑起一个 API,简直是前端人的“后端速效救心丸”。
更重要的是,我们团队现在主打 Flutter + Web 双端,JS 生态无缝衔接。而且我在 GitHub 上扒过不少开源项目(比如 ether.js 这种区块链库),发现好多轻量级后端都是用 Node 写的——不是因为多牛,而是因为“快”。
从 npm init 开始:别被仪式感吓到
很多人一听说“后端开发”,脑子里就浮现出 Nginx、Docker、K8s、MySQL 集群……打住!Node.js 新手根本不需要这些。
你只需要:
mkdir my-node-server
cd my-node-server
npm init -y
npm install express
然后新建 index.js:
const express = require('express');
const app = express();
const PORT = 3000;
app.get('/ping', (req, res) => {
res.json({ message: 'pong from Node.js!' });
});
app.listen(PORT, () => {
console.log(`🚀 Server running on http://localhost:${PORT}`);
});
跑起来:node index.js,浏览器打开 http://localhost:3000/ping,看到 { "message": "pong from Node.js!" } —— 恭喜,你已经是全栈工程师了(至少简历上可以这么写了)。
实战踩坑:从“能跑”到“能上线”
当然,现实没那么美好。我那个埋点需求,光有 /ping 是不够的。我需要:
- 接收 POST 数据
- 存进数据库
- 支持并发(虽然我们用户量还没破千)
- 别崩(求你了)
于是问题来了:
1. POST 数据怎么拿?
一开始我傻乎乎地直接 req.body,结果返回 undefined。查了半天才发现要加中间件:
app.use(express.json()); // 解析 JSON body
app.use(express.urlencoded({ extended: true })); // 解析 form data
血泪教训:Node.js 的“灵活”有时候就是“你得自己记得装轮子”。
2. 数据库存哪儿?
我不想折腾 MySQL,就选了 SQLite(文件型数据库,适合小项目)。但后来测试同学说“线上环境不能用 SQLite”,我只好换成 MongoDB Atlas(免费 tier 够用了)。
连接代码长这样:
const { MongoClient } = require('mongodb');
const client = new MongoClient('your-mongodb-uri');
await client.connect();
const db = client.db('tracking');
const events = db.collection('user_events');
开发心得:别在本地用 SQLite,线上用 MongoDB——类型不一致迟早出事。统一用 MongoDB,开发测试生产环境一致,少掉一半头发。
3. 异步处理 & 错误边界
有一次我忘加 try/catch,用户发了个非法 JSON,整个服务直接 crash。运维大哥在群里 @ 我:“兄弟,你这服务又挂了,监控都报警三次了。”
从此我养成了习惯:每个 async handler 都包一层错误处理。
app.post('/track', async (req, res) => {
try {
await events.insertOne(req.body);
res.status(201).json({ ok: true });
} catch (err) {
console.error('DB error:', err);
res.status(500).json({ error: 'Server error' });
}
});
区块链?别慌,我只是顺便提一嘴
说到这儿,你可能会问:“你标题里不是有‘区块链’吗?怎么全是 Node.js?”
哈哈,确实有点标题党。不过我在 GitHub 上研究过几个轻量级区块链 demo(比如用 JS 实现的简易 PoW 链),它们的节点通信层很多都是用 Node.js 写的 WebSocket 服务。比如:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (data) => {
// 广播交易 or 区块
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
});
});
虽然我们项目暂时用不上区块链,但了解这种模式对我理解“实时数据同步”很有帮助——Flutter 做 UI,Node.js 做消息中转,简直天作之合。
最佳实践总结:别再重蹈我的覆辙
经过这次“被迫全栈”的经历,我整理了几条 Node.js 新手避坑指南:
| 问题 | 错误做法 | 正确姿势 |
|---|---|---|
| 日志 | console.log 到处乱打 |
用 winston 或 pino 结构化日志 |
| 环境配置 | 硬编码数据库密码 | 用 .env + dotenv,千万别提交到 GitHub |
| 代码组织 | 所有逻辑塞在一个文件 | 拆成 routes/, controllers/, models/ |
| 错误处理 | 不处理或随便 res.send(err) |
统一错误中间件 + 返回标准格式 |
| 启动方式 | 直接 node index.js |
用 nodemon 开发,pm2 生产 |
特别提醒:.env 文件一定要加到 .gitignore!上周我们实习生不小心把测试数据库密码推到 GitHub 公开 repo,被安全组抓去喝茶了——场面一度非常尴尬。
工具链推荐:提升幸福感的小东西
- Postman:测 API 必备,比 curl 友好多了
- VSCode + Thunder Client:轻量级 Postman 替代,不用切窗口
- Nodemon:改代码自动重启,告别手动 Ctrl+C + ↑ + Enter
- Prisma(可选):如果你用 PostgreSQL/MySQL,Prisma 的 ORM 真香,TypeScript 支持完美
最后:Node.js 不是银弹,但够快
说实话,Node.js 并不适合所有场景。如果你要做高计算、低延迟的系统(比如高频交易、游戏后端),Go 或 Rust 可能更合适。但在快速验证想法、搭 MVP、做内部工具这类场景下,Node.js 的开发速度真的无敌。
我那个埋点服务,从零到上线只用了两天(包括写文档和给测试同学演示)。虽然代码可能不够“优雅”,但它跑起来了,没崩,老板满意了——这就够了。
所以,如果你也是一个被产品经理“赶鸭子上架”的前端/移动端开发者,别怕。Node.js 没那么可怕,它只是 JavaScript 换了个地方跑而已。
毕竟,在深圳这片土地上,不会点全栈,都不好意思说自己是程序员(狗头保命)。
GitHub 上搜 express starter,fork 一个项目,改改路由,今晚就能吹“我搞了个后端”。
说不定哪天,你也能在简历上写:“精通前后端,擅长用 Node.js 为产品需求擦屁股”。
完。

评论 0