Node.js新手教程:从零开始,写一个属于你的服务器端服务
背景:前端也需要懂后端的时代来了

作为一名在互联网公司工作的前端工程师,我曾经也以为自己的世界只需要围绕HTML、CSS和JavaScript打转。但随着近几年前端工程化的深入发展,以及Vue/React等框架的广泛应用,很多项目都需要我们具备前后端联调的能力,甚至有些小型项目直接要求前端“全栈开发”。
正是在这种背景下,我第一次接触到Node.js。
那是一个中型商城项目的管理后台重构任务。原本由Java同学负责的后端API部分因为团队调整迟迟未能上线,为了不影响整体进度,我们决定先用Node.js快速搭建一个Mock Server,并顺手练练手。没想到这个临时方案后来竟然演变成了一个完整的服务层架构,而我,也正式踏上了学习Node.js之路。
问题描述:为什么选择Node.js?

刚开始的时候,其实我也有点犹豫:为什么不直接继续使用Java或者Python?毕竟它们在后端已经很成熟了。
但几个现实的问题摆在面前:
- 开发效率问题:项目时间紧,如果从头学Java Spring Boot或Django肯定来不及;
- 技能重用问题:既然我已经熟悉JavaScript,那就应该尽可能发挥优势;
- 团队协作问题:前端组统一用Node.js搭建中间层服务,可以极大减少沟通成本;
- 异步处理能力:大量接口涉及外部API调用(如第三方物流、支付系统),Node.js天生适合非阻塞I/O操作。
这些问题让我下定决心尝试Node.js。不过,真正上手之后才发现,它远比我想象中强大得多——当然,也更复杂得多。
解决方案:从Hello World到RESTful API

我给自己定了一个目标:两周内掌握基本的Node.js开发流程,并独立完成Mock Server的搭建。下面是我一步步走下来的路径。
Step 1:Hello World起步
第一步当然是最基础的Node.js入门。
// index.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
执行 node index.js,打开浏览器访问 localhost:3000,就能看到熟悉的“Hello World”了。
小插曲:我一开始误以为Node.js就是写一些JS脚本跑在服务端,结果写了个DOM操作的代码,死活报错……这才意识到要完全切换思路,Node.js是运行在V8引擎上的,没有DOM/BOM,得依赖模块才行。
Step 2:引入Express简化路由处理
原生的http模块虽然能工作,但写起来太原始了。于是我选择了社区广泛使用的Express框架。
安装Express:
npm init -y
npm install express
然后写了第一个简单的GET接口:
// app.js
const express = require('express');
const app = express();
const PORT = 3000;
app.get('/api/products', (req, res) => {
res.json([
{ id: 1, name: '商品A', price: 99 },
{ id: 2, name: '商品B', price: 199 },
]);
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
这样就已经有了一个REST风格的接口。通过Postman测试发现一切正常。
Step 3:加入中间件实现CORS和日志记录
真实项目中,前端和Node.js服务一般不在同一个域名下,所以需要加CORS支持。同时,调试时需要查看请求日志。
npm install cors morgan
// app.js 新增
const cors = require('cors');
const logger = require('morgan');
app.use(cors()); // 允许所有来源的跨域请求
app.use(logger('dev')); // 输出HTTP请求日志
这时候的服务已经能接受跨域请求,并且能看到类似如下的日志信息:
GET /api/products 200 35 - 2.123 ms
非常直观,也很方便调试。
Step 4:数据库连接 & 接口完善
接下来就要接入真正的数据源了。我们用的是MySQL,所以我选用了Sequelize作为ORM工具。
安装依赖:
npm install sequelize mysql2
简单配置Sequelize:
// config/db.js
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
});
module.exports = sequelize;
创建模型Product:
// models/Product.js
const db = require('../config/db');
const Product = db.define('product', {
name: {
type: Sequelize.STRING,
allowNull: false
},
price: Sequelize.FLOAT
}, {
timestamps: false
});
module.exports = Product;
接口中调用:
app.get('/api/products', async (req, res) => {
const products = await Product.findAll();
res.json(products);
});
这个时候,接口就能返回真实的数据了。我们还顺手加上了POST方法:
app.post('/api/products', async (req, res) => {
const data = req.body;
const product = await Product.create(data);
res.status(201).json(product);
});
前端传JSON过来就能创建新商品了。
Step 5:环境变量与配置分离
本地开发和生产部署的数据库地址不可能一样,所以我们需要用环境变量来管理这些配置。
安装dotenv模块:
npm install dotenv
创建 .env 文件:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=123456
DB_NAME=myshop
修改db配置文件:
require('dotenv').config();
const sequelize = new Sequelize({
database: process.env.DB_NAME,
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST,
dialect: 'mysql'
});
这样就完成了本地环境的配置隔离。
踩坑经验:那些年我踩过的Node.js大坑

坑一:忘记加 await,导致异步函数没等待
写了一个删除接口:
app.delete('/api/products/:id', async (req, res) => {
const id = req.params.id;
await Product.destroy({ where: { id } });
res.status(204).end();
});
看起来没问题吧?但我有一次删完数据之后直接跳回列表页,结果页面里还有刚删掉的商品,最后才发现是忘记加 await……
这种错误一旦发生在生产环境后果严重。建议大家多检查异步函数调用是否有await。
坑二:Node.js版本不兼容,导致某些库无法使用
项目中期升级Node.js版本,从v14升级到v18,结果某库(比如bcrypt)不兼容报错:
Error: The module '/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 83. This version of Node.js requires
NODE_MODULE_VERSION 108.
解决方法很简单,清缓存并重新安装依赖即可:
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
建议大家使用nvm管理Node.js版本,避免版本混乱。
坑三:跨域问题没处理清楚
有时候前端会说:“你这个服务又跨域了!”但实际上并不是Node.js的问题。可能是:
- 设置了错误的允许来源(应该设置为具体域名而不是*)
- 请求携带了Cookie但未设置
credentials: true - 预检请求OPTIONS未正确响应
解决方案:
const corsOptions = {
origin: 'http://front-end-domain.com',
credentials: true
};
app.use(cors(corsOptions));
还要注意Nginx等反向代理的配置是否会干扰CORS设置。
代码实践:完整的项目结构推荐
经过几个月的积累,我现在习惯的Node.js项目目录结构如下:
my-api/
├── app.js # 入口文件
├── .env # 环境变量
├── config/
│ └── db.js # 数据库连接配置
├── controllers/
│ └── productController.js # 控制器逻辑分离
├── models/ # 所有数据库模型
│ └── index.js # 模型同步入口
├── routes/ # 路由注册
│ └── productRoutes.js # 商品相关路由定义
├── middleware/ # 自定义中间件
├── utils/ # 工具类函数
└── package.json
例如,把product相关的接口提取成独立的控制器和路由:
controllers/productController.js
const Product = require('../models/Product');
exports.getProducts = async (req, res) => {
const products = await Product.findAll();
res.json(products);
};
routes/productRoutes.js
const express = require('express');
const router = express.Router();
const productController = require('../controllers/productController');
router.get('/products', productController.getProducts);
module.exports = router;
app.js 中引入路由
const productRouter = require('./routes/productRoutes');
app.use('/api', productRouter);
这样的分层结构清晰,维护起来也方便多了。
效果总结:我们的Node.js服务现在什么样?
最终我们的Mock Server不仅满足了前端需求,还逐步承接了多个业务模块的服务化功能,包括:
- 商品管理
- 订单查询
- 用户中心
- 支付回调代理
整个项目上线后运行稳定,性能也相当不错。我们还做了几点优化:
- 使用PM2进程管理工具,保障服务高可用;
- 加入Redis缓存高频查询接口,QPS提升3倍以上;
- 接口文档采用Swagger自动生成,前后端协作更加顺畅;
- 错误日志统一收集到ELK,定位问题更高效。
现在的Node.js服务已经不只是个临时过渡品,而是我们中后台的核心服务之一。
给读者的建议与注意事项
如果你是前端想入门Node.js,这里有几个建议送给你:
✅ 别怕慢,边做边学最重要
- 不一定一开始就追求完美架构,先把功能跑通;
- 多查官方文档和npm包说明,避免造轮子;
- 学会阅读GitHub Issues和Stack Overflow的优质回答。
✅ 前端视角来看待Node.js
- 搭建Mock Server、构建脚本、打包工具配置,都可以结合Node.js完成;
- 可以尝试用Node.js写自己的工具函数库,提高效率;
- 注意前后端交互细节,比如Cookie、Token、CSRF防护等。
✅ 提升体验从工具入手
- 用nodemon监听文件变化自动重启服务;
- 用eslint+prettier保持代码风格一致;
- 用jest+mocha+supertest写单元测试,确保接口稳定性;
- 用swagger-jsdoc生成漂亮的在线文档。
✅ 关注性能和安全
- 不要在生产环境用console.log打太多日志;
- 对用户输入做好校验,防止SQL注入、XSS攻击;
- 使用HTTPS加密通信;
- 合理使用缓存策略,减轻数据库压力;
- 对关键接口限流防刷,避免突发流量打崩服务。
写在最后:Node.js只是起点,不是终点

从最初的一个小需求开始,到现在能用Node.js搞定大部分后端接口,这趟旅程并不轻松,但也收获颇丰。如今我不仅能更快地响应前端需求,也能更好地理解后端的逻辑和挑战。
Node.js不是万能的,但它确实给前端打开了一扇新的窗户。希望我的经历能帮助你少走弯路,在探索的路上走得更快、更远。
如果你也在用Node.js,欢迎留言交流,一起进步 🤝!
配套Demo源码地址(请替换为自己的GitHub仓库):
https://github.com/yourname/nodejs-tutorial-sample
有任何问题,也可以随时联系我 👉 yourmail@example.com
Happy Coding!

评论 0