需要熟悉 JavaScript 前端开发,JS指路:

https://blog.csdn.net/2402_88266590/article/details/159758028

1. Node.js 是什么

1.1 为什么要学后端

作为前端开发者,已经能用 HTML、CSS、JavaScript 做出漂亮的网页。但这些网页是“静态”的——数据写死在代码里,不能保存用户的评论,不能登录,不能上传文件。

后端就是负责处理这些“动态”逻辑的部分:保存数据、验证用户身份、处理请求、返回数据给前端。

学会后端,你就能:

  • 做出完整的网站(如博客、电商、论坛)
  • 理解整个 Web 应用的工作流程
  • 不再依赖别人的接口,自己能写接口
  • 成为“全栈开发者”,就业竞争力更强

1.2 Node.js 是什么、能做什么

Node.js 是一个让 JavaScript 可以运行在服务器端的平台。

以前,JavaScript 只能在浏览器里跑。Node.js 把它带到了服务器上,这意味着你可以用同一种语言(JavaScript)写前端和后端。

Node.js 能做什么?

用途 说明
搭建 Web 服务器 处理 HTTP 请求,返回 HTML、JSON 等
开发 API 接口 提供数据给前端(如用户列表、商品信息)
操作数据库 连接 MongoDB、MySQL,读写数据
实时通信 聊天室、游戏、协作工具(WebSocket)
命令行工具 如 Webpack、Vite、ESLint 都是 Node.js 写的
文件操作 读写服务器上的文件(图片、文本等)

1.3 安装 Node.js 与 npm

1. 下载安装

  • 打开官网:https://nodejs.org
  • 下载 LTS 版本(长期支持版,稳定)
  • 双击安装,一路下一步

2. 验证安装

打开终端(命令行),输入:

node -v

看到版本号(如 v20.10.0),说明安装成功。

npm -v

npm 是 Node.js 自带的包管理器,用来安装第三方库。

1.4 第一个 Node 程序

创建一个文件 hello.js,写入:

console.log('Hello, Node.js!')

在终端中运行:

node hello.js

输出:Hello, Node.js!

你已经用 Node.js 执行了第一段代码!虽然它只是在控制台打印文字,但你已经学会了运行 Node 程序的基本方法。

注意:Node.js 没有浏览器环境,不能使用 alertdocumentwindow 等 API,但有自己特有的模块(如 fshttp

2. Node.js 核心概念

2.1 模块系统 require / exports

Node.js 采用 CommonJS 模块规范,每个文件都是一个模块,内部变量和函数默认不对外暴露。

1. 导出 exports 

// math.js
const add = (a, b) => a + b
const multiply = (a, b) => a * b

// 导出多个
module.exports = { add, multiply }

// 或者逐个导出
// exports.add = add
// exports.multiply = multiply

2. 导入 require

// app.js
const math = require('./math.js')

console.log(math.add(2, 3))      // 5
console.log(math.multiply(2, 3)) // 6

3. 内置模块导入

Node.js 自带了很多内置模块,直接 require 即可:

const fs = require('fs')
const path = require('path')

2.2 读写文件:fs 模块

fs 模块提供了文件读写能力。

1. 读取文件

const fs = require('fs')

// 同步读取
const data = fs.readFileSync('./test.txt', 'utf-8')
console.log(data)

// 异步读取(推荐)
fs.readFile('./test.txt', 'utf-8', (err, data) => {
  if (err) throw err
  console.log(data)
})

2. 写入文件

fs.writeFileSync('./output.txt', 'Hello Node')
// 或异步
fs.writeFile('./output.txt', 'Hello Node', (err) => {
  if (err) throw err
  console.log('写入成功')
})

2.3 路径处理:path 模块

path 模块用来处理文件和目录路径,避免手动拼接字符串导致的跨平台问题(Windows 用 \,Linux/macOS 用 /)。

const path = require('path')

// 拼接路径
const fullPath = path.join('/user', 'local', 'bin', 'app.js')
console.log(fullPath) // \user\local\bin\app.js (Windows) 或 /user/local/bin/app.js (其他)

// 获取文件扩展名
const ext = path.extname('index.html')
console.log(ext) // .html

// 获取文件名
const base = path.basename('/a/b/c/file.txt')
console.log(base) // file.txt

2.4 自己写一个 Web 服务器

Node.js 内置了 http 模块,可以创建 HTTP 服务器。

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, () => {
  console.log('Server running at http://localhost:3000')
})

运行代码后,浏览器访问 http://localhost:3000,就能看到 Hello World

虽然这个服务器很简单,但它展示了 Node.js 处理 HTTP 请求的基本原理。实际开发中,我们会用 Express 等框架简化代码。

2.5 package.json 与依赖管理

1. 初始化项目

npm init -y

生成 package.json 文件,内容如下:

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

2. 安装第三方包

npm install express

安装后,package.json 的 dependencies 字段会新增 express,同时生成 node_modules 文件夹和 package-lock.json

3. 运行脚本

在 scripts 中添加自定义命令:

"scripts": {
  "start": "node app.js",
  "dev": "nodemon app.js"
}

然后可以用 npm run start 或 npm run dev 运行。

3. Express 框架入门

3.1 Express优点

原生 Node.js 的 http 模块功能很基础,写一个稍微复杂的 Web 应用会非常繁琐:

  • 需要手动解析 URL、查询参数、请求体
  • 路由逻辑要用 if/else 嵌套
  • 没有方便的中间件机制

Express 是一个轻量级的 Web 框架,它:

  • 简化了路由定义(app.get('/user', handler)
  • 自动解析请求参数和请求体
  • 支持中间件,能灵活处理日志、权限、错误等
  • 生态丰富,大量第三方中间件可用

可以说,Express 是 Node.js 世界里最流行的 Web 框架

3.2 安装 Express

1. 安装

在项目目录下执行:

npm install express

2. 第一个接口

创建 app.js

const express = require('express')
const app = express()

// 定义一个 GET 接口
app.get('/', (req, res) => {
  res.send('Hello Express!')
})

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000')
})

运行 node app.js,浏览器访问 http://localhost:3000,你会看到 Hello Express!

说明

1. app.get() 表示监听 GET 请求

2. res.send() 可以自动根据内容类型返回文本、HTML、JSON

3.3 路由 GET / POST / PUT / DELETE

// GET:获取数据
app.get('/users', (req, res) => {
  res.send('获取用户列表')
})

// POST:新增数据
app.post('/users', (req, res) => {
  res.send('创建用户')
})

// PUT:更新数据
app.put('/users/:id', (req, res) => {
  res.send(`更新用户 ${req.params.id}`)
})

// DELETE:删除数据
app.delete('/users/:id', (req, res) => {
  res.send(`删除用户 ${req.params.id}`)
})

测试这些接口可以用浏览器(只能测 GET)或 Postman / Thunder Client 插件。

3.4 获取请求参数 query、params、body 

URL 查询参数 query 

例如 GET /search?keyword=apple&page=2

app.get('/search', (req, res) => {
  const { keyword, page } = req.query
  res.send(`搜索关键词:${keyword},第 ${page} 页`)
})

动态路径参数 params 

例如 GET /users/123

app.get('/users/:id', (req, res) => {
  const userId = req.params.id
  res.send(`用户 ID:${userId}`)
})

请求体 body

POST / PUT 请求常带着 JSON 数据,需要先启用 Express 的 JSON 解析中间件:

app.use(express.json())   // 解析 JSON 请求体

app.post('/login', (req, res) => {
  const { username, password } = req.body
  res.send(`收到登录请求:${username} / ${password}`)
})

3.5 返回数据 res.send、res.json、res.status

// 返回普通文本
app.get('/text', (req, res) => {
  res.send('纯文本')
})

// 返回 JSON
app.get('/json', (req, res) => {
  res.json({ name: '张三', age: 18 })
})

// 返回状态码 + JSON
app.post('/create', (req, res) => {
  // 假设创建成功
  res.status(201).json({ message: '创建成功' })
})

// 重定向
app.get('/old', (req, res) => {
  res.redirect('/new')
})

// 返回 404
app.get('/notfound', (req, res) => {
  res.status(404).send('页面不存在')
})

4. 路由与中间件

4.1 路由模块化 express.Router

当项目变大时,把所有路由写在 app.js 里会变得混乱。可以用 express.Router() 拆分路由。

1. 创建单独的路由文件

// routes/users.js
const express = require('express')
const router = express.Router()

// 这里的路径会拼接到父路径后面
router.get('/', (req, res) => {
  res.send('用户列表')
})

router.get('/:id', (req, res) => {
  res.send(`用户 ${req.params.id} 的详情`)
})

router.post('/', (req, res) => {
  res.send('创建用户')
})

module.exports = router

2. 在主应用中使用

// app.js
const express = require('express')
const app = express()

const userRouter = require('./routes/users')

// 所有 /users 开头的请求交给 userRouter 处理
app.use('/users', userRouter)

app.listen(3000)

在访问 /users/users/123POST /users 都会走对应的子路由。

4.2 中间件是什么?

中间件是在请求到达最终处理函数之前或之后执行的函数。它可以:

  • 执行任意代码
  • 修改请求/响应对象
  • 结束请求-响应循环
  • 调用下一个中间件

一个简单的中间件示例:

// 日志中间件
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`)
  next()   // 必须调用 next() 才能继续
})

app.get('/', (req, res) => {
  res.send('首页')
})

4.3 中间件对比

类型 作用范围 示例
应用级中间件 整个应用 app.use(logger)
路由级中间件 某个路由或路由组 router.use(authMiddleware)
// 应用级:所有请求都会经过
app.use((req, res, next) => {
  console.log('全局中间件')
  next()
})

// 路由级:只对 /admin 下的请求生效
const adminRouter = require('./routes/admin')
app.use('/admin', adminRouter)

4.4 内置中间件 json、静态文件

Express 自带几个常用中间件:

express.json():解析 JSON 请求体

app.use(express.json())

express.urlencoded():解析表单数据

app.use(express.urlencoded({ extended: true }))

express.static():提供静态文件服务(图片、CSS、JS)

app.use(express.static('public'))

将图片放在 public 文件夹,即可通过 /logo.png 直接访问。

4.5 常用第三方中间件 morgan、cors 

morgan:日志中间件

npm install morgan
const morgan = require('morgan')
app.use(morgan('tiny'))   // 输出简略日志

访问任意接口,控制台会打印类似 GET /users 200 2.123 ms 的日志。

cors:解决跨域问题

npm install cors
const cors = require('cors')
app.use(cors())   // 允许所有跨域请求

如果不加 CORS,前端从不同端口(如 5173)请求后端(3000)会报跨域错误。

5. 数据库入门

5.1 MongoDB

之前的接口数据都写在代码里,重启服务器就会丢失。数据库用来持久化存储数据(用户信息、文章、订单等)。

关系型数据库(MySQL、PostgreSQL)像 Excel 表格,有行有列。
文档型数据库(MongoDB)像 JSON 对象,更贴合 JavaScript 开发习惯。

MongoDB 的特点:

  • 不需要预先定义表结构
  • 数据格式灵活
  • 与 Node.js 配合很顺手

5.2 MongoDB 安装与基本操作

安装 MongoDB

本地安装(开发测试):

或者使用云服务(推荐新手)
MongoDB Atlas 提供免费 500MB 云数据库,无需安装,注册即可使用。

基本操作

终端

# 进入 MongoDB 命令行
mongosh

# 查看所有数据库
show dbs

# 使用(或创建)数据库
use mydb

# 查看当前数据库下的集合
show collections

# 插入一条数据
db.users.insertOne({ name: '张三', age: 18 })

# 查询数据
db.users.find()

# 删除数据库
use mydb
db.dropDatabase()

5.3 用 Mongoose 连接数据库

Mongoose 是 Node.js 环境里操作 MongoDB 的 ODM(对象文档映射),提供 Schema 和数据校验。

安装 Mongoose

npm install mongoose

连接数据库

// db.js
const mongoose = require('mongoose')

mongoose.connect('mongodb://localhost:27017/myapp')
  .then(() => console.log('数据库连接成功'))
  .catch(err => console.error('连接失败:', err))

如果用 Atlas 云数据库,连接字符串类似:

mongodb+srv://用户名:密码@cluster0.xxx.mongodb.net/myapp

5.4 定义数据模型 Schema

Mongoose 用 Schema 定义数据的字段和类型。

// models/User.js
const mongoose = require('mongoose')

const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  age: { type: Number, min: 0, max: 150 },
  email: { type: String, required: true, unique: true },
  createdAt: { type: Date, default: Date.now }
})

module.exports = mongoose.model('User', userSchema)

字段类型:String、Number、Date、Boolean、Array、ObjectId 等。

5.5 增删改查 CRUD

const User = require('./models/User')

// 新增
const newUser = new User({ name: '李四', age: 22, email: 'li@example.com' })
await newUser.save()

// 查询所有
const users = await User.find()

// 条件查询
const user = await User.findOne({ email: 'li@example.com' })

// 更新
await User.updateOne({ name: '李四' }, { age: 23 })

// 删除
await User.deleteOne({ name: '李四' })

在 Express 路由中使用:

app.get('/users', async (req, res) => {
  const users = await User.find()
  res.json(users)
})

app.post('/users', async (req, res) => {
  const user = new User(req.body)
  await user.save()
  res.status(201).json(user)
})

6 错误处理与调试

6.1 try/catch 捕获同步错误

同步代码中,错误可以用 try/catch 捕获。

app.get('/error', (req, res) => {
  try {
    const data = JSON.parse('invalid json')
    res.json(data)
  } catch (err) {
    res.status(500).json({ error: err.message })
  }
})

6.2 异步错误处理 Express 5

异步代码(async/await)中的错误如果不捕获,Express 不会自动处理。
Express 5 原生支持异步错误自动传递到全局错误处理中间件。

app.get('/async-error', async (req, res) => {
  const user = await User.findById('invalid-id')   // 会抛错
  res.json(user)
})

在 Express 5 中,这样的错误会被自动捕获。Express 4 则需手动 catch 并调用 next()

app.get('/async-error', async (req, res, next) => {
  try {
    const user = await User.findById('invalid-id')
    res.json(user)
  } catch (err) {
    next(err)
  }
})

6.3 全局错误处理中间件

定义一个放在所有路由最后的错误处理中间件,统一返回错误格式。

// 在所有路由之后
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).json({ error: err.message || '服务器内部错误' })
})

6.4 nodemon 自动重启服务

每次修改代码都要手动重启,很麻烦。nodemon 可以监听文件变化,自动重启。

npm install -g nodemon
# 或项目内安装
npm install -D nodemon

在 package.json 中添加脚本:

"scripts": {
  "dev": "nodemon app.js"
}

6.5 调试技巧

使用 console.log

console.log('当前用户:', user)
console.error('出错了', err)

VS Code 内置调试

  1. 点击左侧“运行和调试”图标
  2. 创建 launch.json,选择 Node.js 环境
  3. 在代码行号左侧点击设置断点
  4. 按 F5 启动调试

更专业的工具推荐 Thunder Client(VS Code 插件)或 Postman 测试接口。

7. 部署上线

7.1 环境变量管理 .env

项目中有一些信息不应该写死在代码里,例如数据库密码、JWT 密钥、API 密钥等。不同环境(开发、生产)还可能使用不同的配置。

使用 dotenv 包

npm install dotenv

项目根目录创建 .env 文件:

PORT=3000
DB_URL=mongodb://localhost:27017/myapp
JWT_SECRET=mySuperSecretKey

在 app.js 开头引入:

require('dotenv').config()

const port = process.env.PORT || 3000
const dbUrl = process.env.DB_URL

console.log(`Server running on port ${port}`)

 重要.env 文件绝不能提交到 Git,应在 .gitignore 中忽略。

7.2 部署到 Railway / Render

Railway 和 Render 提供免费后端部署服务,无需自己买服务器。

准备工作

  1. 将项目代码推送到 GitHub 仓库
  2. 确保 package.json 中有 start 脚本:
"scripts": {
  "start": "node app.js"
}

部署到 Railway

  1. 访问 https://railway.app
  2. 用 GitHub 账号登录
  3. 点击 New Project → Deploy from GitHub repo
  4. 选择你的仓库
  5. Railway 会自动检测 Node.js 项目并部署
  6. 部署完成后会生成一个公网 URL(如 https://myapp.up.railway.app

设置环境变量:在 Railway 控制台 → 项目 → Variables → 添加 DB_URLJWT_SECRET 等。

部署到 Render

  1. 访问 https://render.com
  2. 用 GitHub 登录
  3. 点击 New + → Web Service
  4. 连接 GitHub 仓库
  5. 填写:

        Name:项目名称

        Environment:Node

        Build Command:npm install

        Start Command:npm start

        点击 Create Web Service

部署完成后,服务地址类似 https://myapp.onrender.com

同样需要在 Dashboard → Environment 中添加环境变量。

7.3 部署到 Vercel Serverless

Vercel 通常用于前端静态网站,但也支持 Node.js Serverless 函数。适合简单 API,不适合 WebSocket 或长时间连接。

配置

项目根目录创建 vercel.json

{
  "version": 2,
  "builds": [
    {
      "src": "app.js",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "app.js"
    }
  ]
}

修改 app.js 导出为 Serverless 函数:

// 去掉 app.listen,改为导出 app
module.exports = app

部署

npm install -g vercel
vercel

按提示登录并关联项目,Vercel 会自动部署并返回域名。

7.4 日志与监控

1. 日志

生产环境建议使用更专业的日志库代替 console.log

npm install winston

简单配置:

const winston = require('winston')
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
})

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({ format: winston.format.simple() }))
}

2. 监控

  • Railway / Render 自带:平台提供简单的日志查看和监控面板
  • UptimeRobot(免费):定期 ping 你的 API,宕机时发邮件通知
  • Sentry:捕获异常并上报(适合大型项目)

8. 附录

8.1 常用 npm 包推荐

包名 用途
express Web 框架
mongoose MongoDB 对象建模
dotenv 环境变量管理
cors 跨域支持
morgan HTTP 请求日志
bcryptjs 密码加密
jsonwebtoken JWT 身份认证
joi 请求参数校验
winston 日志记录
nodemon 开发时热重启
helmet 安全头设置
express-rate-limit 接口限流

8.2 HTTP 状态码速查

状态码 含义 场景
200 OK 请求成功
201 Created 创建成功(如 POST)
204 No Content 删除成功,无返回体
400 Bad Request 参数错误、格式不对
401 Unauthorized 未认证(未登录)
403 Forbidden 无权限
404 Not Found 资源不存在
409 Conflict 资源冲突(如重复注册)
500 Internal Server Error 服务器内部错误

8.3 推荐学习资源

1. 文档

2. 实战

  • Build a REST API with Node.js and Express:YouTube 上搜索

  • 全栈之巅 – Node.js 教程:B站优质中文教程

3. 在线练习

  • Postman:接口测试利器

  • Thunder Client:VS Code 插件,轻量替代 Postman

更多推荐