# 这是针对 Node.js 后端项目的工具类模块
# 让我们先总结
目录结构:
/project-root
|-- controllers
| |-- blogs.js
|-- models
| |-- blog.js
|-- node_modules
|-- requests
| |-- create_note.rest
|-- utils
| |-- config.js
| |-- logger.js
| |-- middleware.js
|-- .env
|-- .gitignore
|-- app.js
|-- index.js
|-- package-lock.json
|-- package.json
# app.js (核心入口)
这里是应用程序主配置文件
这里发生的事:
- 初始化 Express 应用
- 连接 MongoDB 数据库
- 注册全局中间件 (cors、JSON 解析、请求日志)
- 挂载博客路由到
/api/blogs
路径 - 配置错误处理中间件
# index.js (服务启动器)
这里是服务器启动入口
这里发生的事:
- 创建 HTTP 服务器
- 监听配置端口
- 启动时输出运行日志
# models/blog.js (数据层核心)
这里是 Mongoose 数据模型
这里发生的事:
- 定义博客数据模型 (title、author、url、likes)
- 配置数据转换逻辑 (隐藏_id 和_v, 暴露 id)
- 提供数据操作接口
# controllers/blogs.js (业务逻辑层)
这是一个路由控制器
这里发生的事:
- 处理
/api/blogs
的 GET/POST 请求 - 调用 Mongoose 模型进行数据库操作
- 返回 JSON 格式响应
# utils/middleware.js (中间件)
这里发生的事:
- 配置全局错误处理中间件
- 配置请求日志中间件
- 配置响应头中间件
- 配置响应体中间件
- 配置请求参数中间件
# utils/logger.js (日志)
这里发生的事:
- 配置日志输出格式
- 配置日志输出级别
# utils/config.js (配置)
这里发生的事:
- 配置数据库连接地址
- 配置日志输出路径
- 设置端口
# 最后再开始
以一个初始的博客列表应用的后端代码出发:
const http = require('http') | |
const express = require('express') | |
const app = express() | |
const cors = require('cors') | |
const mongoose = require('mongoose') | |
const blogSchema = new mongoose.Schema({ | |
title: String, | |
author: String, | |
url: String, | |
likes: Number | |
}) | |
const Blog = mongoose.model('Blog', blogSchema) | |
const mongoUrl = 'mongodb://localhost/bloglist' | |
mongoose.connect(mongoUrl) | |
app.use(cors()) | |
app.use(express.json()) | |
app.get('/api/blogs', (request, response) => { | |
Blog | |
.find({}) | |
.then(blogs => { | |
response.json(blogs) | |
}) | |
}) | |
app.post('/api/blogs', (request, response) => { | |
const blog = new Blog(request.body) | |
blog | |
.save() | |
.then(result => { | |
response.status(201).json(result) | |
}) | |
}) | |
const PORT = 3003 | |
app.listen(PORT, () => { | |
console.log(`Server running on port ${PORT}`) | |
}) |
# blog.js 模型
const mongoose = require('mongoose'); | |
const blogSchema = new mongoose.Schema({ | |
title: String, | |
author: String, | |
url: String, | |
likes: Number | |
}) | |
blogSchema.set('toJSON', { | |
transform: (document, returnedObject) => { | |
returnedObject.id = returnedObject._id.toString() | |
delete returnedObject._id | |
delete returnedObject.__v | |
} | |
}) | |
module.exports = mongoose.model('Blog', blogSchema); |
# blogs.js 控制器
const blogsRouter = require('express').Router() | |
const Blog = require('../models/blog') | |
blogsRouter.get('/', (request, response) => { | |
Blog | |
.find({}) | |
.then(blogs => { | |
response.json(blogs) | |
}) | |
}) | |
blogsRouter.post('/', (request, response) => { | |
const blog = new Blog(request.body) | |
blog | |
.save() | |
.then(result => { | |
response.status(201).json(result) | |
}) | |
}) | |
module.exports = blogsRouter |
# app.js 配置
const config = require('./utils/config') | |
const express = require('express') | |
const app = express() | |
const cors = require('cors') | |
const blogsRouter = require('./controllers/blogs') // 路由器 | |
const middleware = require('./utils/middleware') // 中间件 | |
const logger = require('./utils/logger') // 日志 | |
const mongoose = require('mongoose') // mongoose | |
mongoose.set('strictQuery', false) | |
logger.info('connecting to', config.MONGODB_URI) | |
mongoose.connect(config.MONGODB_URI) // 连接数据库 | |
.then(() => { | |
logger.info('connected to MongoDB') | |
}) | |
.catch((error) => { | |
logger.error('error connecting to MongoDB:', error.message) | |
}) | |
app.use(cors()) | |
app.use(express.json()) | |
app.use(middleware.requestLogger); | |
app.use('/api/blogs', blogsRouter); | |
app.use(middleware.unknownEndpoint); | |
app.use(middleware.errorHandler); | |
module.exports = app; |
# index.js 启动
const app = require('./app') | |
const http = require('http') | |
const config = require('./utils/config') | |
const logger = require('./utils/logger') | |
const server = http.createServer(app); | |
server.listen(config.PORT, () => { | |
logger.info(`Server running on port ${config.PORT}`) | |
}) |
# config.js 配置
require('dotenv').config() | |
const PORT = process.env.PORT; | |
const MONGODB_URI = process.env.MONGODB_URI; | |
module.exports = { | |
MONGODB_URI, | |
PORT | |
} |
# logger.js 日志
const info = (...params) => { | |
console.log(...params); | |
} | |
const error = (...params) => { | |
console.error(...params); | |
} | |
module.exports = { | |
info, | |
error | |
} |
# middleware.js 中间件
const logger = require('./logger'); | |
const requestLogger = (request, response, next) => { | |
logger.info('Method:', request.method); | |
logger.info('Path: ', request.path); | |
logger.info('Body: ', request.body); | |
logger.info('---'); | |
next(); | |
}; | |
const unknownEndpoint = (request, response) => { | |
response.status(404).send({ error: 'unknown endpoint' }); | |
}; | |
const errorHandler = (error, request, response, next) => { | |
logger.error(error.message); | |
if (error.name === 'CastError') { | |
return response.status(400).send({ error: 'malformatted id' }); | |
} else if (error.name === 'ValidationError') { | |
return response.status(400).json({ error: error.message }); | |
} | |
next(error); | |
}; | |
module.exports = { | |
requestLogger, | |
unknownEndpoint, | |
errorHandler | |
} |