NodeJs全汇总

Node.js基本概念

Node.js是一个基于Chrome V8 JavaScript引擎的JavaScript运行时环境,让JavaScript可以在服务器端运行。

为什么要使用Node.js

单线程事件循环:Node.js采用单线程事件循环模型,避免了多线程的复杂性
非阻塞I/O:异步I/O操作不会阻塞主线程,提高并发性能
跨平台:可以在Windows、macOS、Linux等操作系统上运行
丰富的生态系统:npm包管理器提供了大量的第三方模块
前后端统一:使用相同的JavaScript语言开发前后端

高性能:基于V8引擎,执行速度快
实时应用:适合构建实时应用,如聊天室、游戏服务器
微服务架构:轻量级,适合构建微服务

Node.js基础

1. 模块系统

概念:Node.js使用CommonJS模块系统,每个文件都是一个模块,可以通过require()导入和module.exports导出。

语法规则

  • 导入模块:const 模块名 = require('模块路径')
  • 导出模块:module.exports = 值exports.属性名 = 值
  • 内置模块:直接使用模块名,如require('fs')
  • 第三方模块:使用包名,如require('express')

作用

  • 代码组织和模块化
  • 避免全局变量污染
  • 提高代码复用性
  • 依赖管理

基本模块使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// math.js - 定义模块
function add(a, b) {
return a + b
}

function subtract(a, b) {
return a - b
}

// 导出模块
module.exports = {
add,
subtract
}

// 或者使用exports
exports.multiply = (a, b) => a * b
exports.divide = (a, b) => a / b
1
2
3
4
5
6
7
8
9
10
11
// main.js - 使用模块
const math = require('./math')
const fs = require('fs') // 内置模块
const express = require('express') // 第三方模块

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

// 解构导入
const { add, subtract } = require('./math')
console.log(add(10, 5)) // 15

ES6模块语法(Node.js 12+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// math.mjs - ES6模块
export function add(a, b) {
return a + b
}

export default function multiply(a, b) {
return a * b
}

// main.mjs - 使用ES6模块
import { add } from './math.mjs'
import multiply from './math.mjs'

console.log(add(5, 3)) // 8
console.log(multiply(4, 2)) // 8

2. 文件系统操作

概念:Node.js提供了fs模块来处理文件系统操作,包括文件的读取、写入、删除等。

语法规则

  • 同步操作:fs.readFileSync(), fs.writeFileSync()
  • 异步操作:fs.readFile(), fs.writeFile()
  • Promise版本:fs.promises.readFile(), fs.promises.writeFile()

使用场景

  • 配置文件读取
  • 日志文件写入
  • 静态文件服务
  • 数据持久化

基本文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const fs = require('fs')
const path = require('path')

// 同步读取文件
try {
const data = fs.readFileSync('config.json', 'utf8')
console.log('配置文件内容:', data)
} catch (error) {
console.error('读取文件失败:', error.message)
}

// 异步读取文件
fs.readFile('data.txt', 'utf8', (err, data) => {
if (err) {
console.error('读取失败:', err.message)
return
}
console.log('文件内容:', data)
})

// Promise方式读取文件
async function readFileAsync(filename) {
try {
const data = await fs.promises.readFile(filename, 'utf8')
return data
} catch (error) {
console.error('读取失败:', error.message)
throw error
}
}

// 写入文件
const content = 'Hello, Node.js!'
fs.writeFile('output.txt', content, (err) => {
if (err) {
console.error('写入失败:', err.message)
return
}
console.log('文件写入成功')
})

// 检查文件是否存在
fs.access('config.json', fs.constants.F_OK, (err) => {
if (err) {
console.log('文件不存在')
} else {
console.log('文件存在')
}
})

目录操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 创建目录
fs.mkdir('new-folder', (err) => {
if (err) {
console.error('创建目录失败:', err.message)
return
}
console.log('目录创建成功')
})

// 读取目录
fs.readdir('./', (err, files) => {
if (err) {
console.error('读取目录失败:', err.message)
return
}
console.log('目录内容:', files)
})

// 获取文件信息
fs.stat('package.json', (err, stats) => {
if (err) {
console.error('获取文件信息失败:', err.message)
return
}
console.log('文件大小:', stats.size)
console.log('创建时间:', stats.birthtime)
console.log('是否文件:', stats.isFile())
console.log('是否目录:', stats.isDirectory())
})

3. 路径处理

概念:Node.js提供了path模块来处理文件和目录路径,确保跨平台兼容性。

语法规则

  • path.join() - 连接路径
  • path.resolve() - 解析绝对路径
  • path.dirname() - 获取目录名
  • path.basename() - 获取文件名
  • path.extname() - 获取文件扩展名

使用场景

  • 构建跨平台路径
  • 文件路径解析
  • 相对路径转绝对路径
  • 路径拼接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const path = require('path')

// 路径拼接
const filePath = path.join('src', 'components', 'Button.js')
console.log(filePath) // src/components/Button.js (Windows: src\components\Button.js)

// 解析绝对路径
const absolutePath = path.resolve('src', 'index.js')
console.log(absolutePath) // /full/path/to/project/src/index.js

// 获取路径各部分
const filePath2 = '/home/user/project/src/index.js'
console.log(path.dirname(filePath2)) // /home/user/project/src
console.log(path.basename(filePath2)) // index.js
console.log(path.extname(filePath2)) // .js

// 路径规范化
const messyPath = '/home/user/../user/./project//src/index.js'
console.log(path.normalize(messyPath)) // /home/user/project/src/index.js

// 相对路径
const from = '/home/user/project/src'
const to = '/home/user/project/dist'
console.log(path.relative(from, to)) // ../dist

4. 环境变量

概念:Node.js通过process.env对象访问环境变量,用于配置应用程序。

语法规则

  • 读取环境变量:process.env.变量名
  • 设置环境变量:process.env.变量名 = 值
  • 使用dotenv包:require('dotenv').config()

使用场景

  • 数据库连接配置
  • API密钥管理
  • 环境特定配置
  • 敏感信息存储
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 读取环境变量
const port = process.env.PORT || 3000
const dbUrl = process.env.DATABASE_URL
const apiKey = process.env.API_KEY

console.log('服务器端口:', port)
console.log('数据库URL:', dbUrl)

// 设置环境变量
process.env.NODE_ENV = 'production'
process.env.DEBUG = 'true'

// 使用dotenv包管理环境变量
// 安装: npm install dotenv
require('dotenv').config()

// .env文件内容:
// PORT=3000
// DATABASE_URL=mongodb://localhost:27017/myapp
// API_KEY=your-secret-key

console.log('配置的端口:', process.env.PORT)
console.log('数据库连接:', process.env.DATABASE_URL)

5. 命令行参数

概念:Node.js可以通过process.argv获取命令行参数,用于创建命令行工具。

语法规则

  • process.argv[0] - Node.js可执行文件路径
  • process.argv[1] - 当前脚本文件路径
  • process.argv[2+] - 用户传入的参数

使用场景

  • 命令行工具开发
  • 脚本参数传递
  • 配置选项设置
  • 批处理操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 获取命令行参数
console.log('Node.js路径:', process.argv[0])
console.log('脚本路径:', process.argv[1])
console.log('用户参数:', process.argv.slice(2))

// 解析命令行参数
const args = process.argv.slice(2)
const options = {}

for (let i = 0; i < args.length; i++) {
if (args[i].startsWith('--')) {
const key = args[i].substring(2)
const value = args[i + 1]
options[key] = value
i++ // 跳过下一个参数
}
}

console.log('解析的选项:', options)

// 使用示例: node script.js --name "张三" --age 25
// 输出: { name: "张三", age: "25" }

6. 全局对象

概念:Node.js提供了一些全局对象,可以直接使用,无需require导入。

主要全局对象

  • global - 全局命名空间
  • process - 进程对象
  • console - 控制台对象
  • Buffer - 缓冲区对象
  • __dirname - 当前文件所在目录
  • __filename - 当前文件完整路径

使用场景

  • 进程管理
  • 调试输出
  • 二进制数据处理
  • 文件路径获取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 全局对象使用
console.log('当前目录:', __dirname)
console.log('当前文件:', __filename)

// process对象
console.log('Node.js版本:', process.version)
console.log('平台:', process.platform)
console.log('架构:', process.arch)
console.log('内存使用:', process.memoryUsage())

// Buffer对象
const buf = Buffer.from('Hello, Node.js!', 'utf8')
console.log('Buffer内容:', buf.toString())
console.log('Buffer长度:', buf.length)

// 全局变量设置
global.myGlobalVar = '这是一个全局变量'
console.log('全局变量:', myGlobalVar)

// 定时器(全局函数)
setTimeout(() => {
console.log('3秒后执行')
}, 3000)

setInterval(() => {
console.log('每秒执行一次')
}, 1000)

Node.js高级特性

1. 异步编程

概念:Node.js的核心特性是异步非阻塞I/O,通过回调函数、Promise和async/await来处理异步操作。

语法规则

  • 回调函数:function(callback) { callback(err, data) }
  • Promise:new Promise((resolve, reject) => { })
  • async/await:async function() { await 异步操作 }

使用场景

  • 文件I/O操作
  • 网络请求
  • 数据库查询
  • 定时任务

回调函数模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const fs = require('fs')

// 回调地狱示例
fs.readFile('file1.txt', 'utf8', (err, data1) => {
if (err) {
console.error('读取file1失败:', err)
return
}

fs.readFile('file2.txt', 'utf8', (err, data2) => {
if (err) {
console.error('读取file2失败:', err)
return
}

fs.writeFile('output.txt', data1 + data2, (err) => {
if (err) {
console.error('写入失败:', err)
return
}
console.log('文件合并完成')
})
})
})

// 改进的回调函数
function readFileCallback(filename, callback) {
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
callback(err, null)
return
}
callback(null, data)
})
}

// 使用改进的回调
readFileCallback('config.json', (err, data) => {
if (err) {
console.error('读取失败:', err)
return
}
console.log('配置内容:', data)
})

Promise模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const fs = require('fs').promises

// 基本Promise使用
function readFilePromise(filename) {
return new Promise((resolve, reject) => {
fs.readFile(filename, 'utf8')
.then(data => resolve(data))
.catch(err => reject(err))
})
}

// Promise链式调用
readFilePromise('file1.txt')
.then(data1 => {
console.log('file1内容:', data1)
return readFilePromise('file2.txt')
})
.then(data2 => {
console.log('file2内容:', data2)
return fs.writeFile('output.txt', data1 + data2)
})
.then(() => {
console.log('文件合并完成')
})
.catch(err => {
console.error('操作失败:', err)
})

// Promise.all并行处理
Promise.all([
fs.readFile('file1.txt', 'utf8'),
fs.readFile('file2.txt', 'utf8'),
fs.readFile('file3.txt', 'utf8')
])
.then(results => {
console.log('所有文件读取完成:', results)
const combined = results.join('\n')
return fs.writeFile('combined.txt', combined)
})
.then(() => {
console.log('文件合并完成')
})
.catch(err => {
console.error('并行处理失败:', err)
})

async/await模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// async/await基本使用
async function readFilesAsync() {
try {
const data1 = await fs.readFile('file1.txt', 'utf8')
const data2 = await fs.readFile('file2.txt', 'utf8')
const combined = data1 + data2
await fs.writeFile('output.txt', combined)
console.log('文件合并完成')
} catch (error) {
console.error('操作失败:', error)
}
}

// 并行处理多个文件
async function readFilesParallel() {
try {
const [data1, data2, data3] = await Promise.all([
fs.readFile('file1.txt', 'utf8'),
fs.readFile('file2.txt', 'utf8'),
fs.readFile('file3.txt', 'utf8')
])

console.log('所有文件读取完成')
const combined = [data1, data2, data3].join('\n')
await fs.writeFile('combined.txt', combined)
console.log('文件合并完成')
} catch (error) {
console.error('并行处理失败:', error)
}
}

// 错误处理
async function handleErrors() {
try {
const data = await fs.readFile('nonexistent.txt', 'utf8')
console.log(data)
} catch (error) {
if (error.code === 'ENOENT') {
console.log('文件不存在')
} else {
console.error('其他错误:', error.message)
}
}
}

2. 事件系统

概念:Node.js基于事件驱动架构,使用EventEmitter类来处理事件。

语法规则

  • 创建事件发射器:new EventEmitter()
  • 监听事件:emitter.on('事件名', 回调函数)
  • 发射事件:emitter.emit('事件名', 数据)
  • 移除监听器:emitter.removeListener('事件名', 回调函数)

使用场景

  • 自定义事件处理
  • 模块间通信
  • 异步操作完成通知
  • 状态变化通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
const EventEmitter = require('events')

// 基本事件使用
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()

// 监听事件
myEmitter.on('event', (data) => {
console.log('收到事件:', data)
})

// 发射事件
myEmitter.emit('event', 'Hello, Event!')

// 只监听一次的事件
myEmitter.once('once-event', (data) => {
console.log('只执行一次:', data)
})

myEmitter.emit('once-event', 'First')
myEmitter.emit('once-event', 'Second') // 不会执行

// 错误事件处理
myEmitter.on('error', (err) => {
console.error('发生错误:', err.message)
})

myEmitter.emit('error', new Error('Something went wrong!'))

// 实际应用示例
class FileWatcher extends EventEmitter {
constructor(filename) {
super()
this.filename = filename
this.watchFile()
}

watchFile() {
const fs = require('fs')
fs.watchFile(this.filename, (curr, prev) => {
this.emit('change', {
filename: this.filename,
current: curr,
previous: prev
})
})
}
}

const watcher = new FileWatcher('config.json')
watcher.on('change', (data) => {
console.log('文件发生变化:', data.filename)
})

3. 流(Stream)

概念:流是Node.js中处理数据的抽象接口,可以高效地处理大量数据。

语法规则

  • 可读流:fs.createReadStream()
  • 可写流:fs.createWriteStream()
  • 双工流:new Duplex()
  • 转换流:new Transform()

使用场景

  • 大文件处理
  • 网络数据传输
  • 实时数据处理
  • 数据转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const fs = require('fs')
const { Transform } = require('stream')

// 基本流操作
const readStream = fs.createReadStream('input.txt')
const writeStream = fs.createWriteStream('output.txt')

// 管道操作
readStream.pipe(writeStream)

readStream.on('data', (chunk) => {
console.log('读取数据块:', chunk.length, 'bytes')
})

readStream.on('end', () => {
console.log('文件读取完成')
})

writeStream.on('finish', () => {
console.log('文件写入完成')
})

// 自定义转换流
class UpperCaseTransform extends Transform {
constructor() {
super()
}

_transform(chunk, encoding, callback) {
const upperChunk = chunk.toString().toUpperCase()
this.push(upperChunk)
callback()
}
}

// 使用转换流
const upperCaseTransform = new UpperCaseTransform()
const readStream2 = fs.createReadStream('input.txt')
const writeStream2 = fs.createWriteStream('output-upper.txt')

readStream2
.pipe(upperCaseTransform)
.pipe(writeStream2)

// 错误处理
readStream.on('error', (err) => {
console.error('读取流错误:', err)
})

writeStream.on('error', (err) => {
console.error('写入流错误:', err)
})

4. 子进程

概念:Node.js可以创建子进程来执行系统命令或其他程序。

语法规则

  • child_process.exec() - 执行shell命令
  • child_process.spawn() - 启动子进程
  • child_process.fork() - 创建新的Node.js进程
  • child_process.execFile() - 执行可执行文件

使用场景

  • 执行系统命令
  • 调用其他程序
  • 多进程处理
  • 系统集成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const { exec, spawn, fork } = require('child_process')

// exec执行shell命令
exec('ls -la', (error, stdout, stderr) => {
if (error) {
console.error('执行错误:', error)
return
}
console.log('命令输出:', stdout)
})

// spawn启动子进程
const ls = spawn('ls', ['-la'])

ls.stdout.on('data', (data) => {
console.log('输出:', data.toString())
})

ls.stderr.on('data', (data) => {
console.error('错误:', data.toString())
})

ls.on('close', (code) => {
console.log('进程退出,代码:', code)
})

// fork创建新的Node.js进程
const child = fork('./child-process.js')

child.on('message', (msg) => {
console.log('收到子进程消息:', msg)
})

child.send({ hello: 'world' })

// child-process.js
process.on('message', (msg) => {
console.log('子进程收到消息:', msg)
process.send({ response: 'Hello from child!' })
})

5. 网络编程

概念:Node.js提供了http、https、net等模块来创建网络应用。

语法规则

  • HTTP服务器:http.createServer()
  • HTTP客户端:http.request()
  • TCP服务器:net.createServer()
  • UDP:dgram.createSocket()

使用场景

  • Web服务器
  • API服务
  • 代理服务器
  • 实时通信
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const http = require('http')
const https = require('https')
const net = require('net')

// HTTP服务器
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
res.end('<h1>Hello, Node.js!</h1>')
})

server.listen(3000, () => {
console.log('HTTP服务器运行在 http://localhost:3000')
})

// HTTP客户端
const options = {
hostname: 'api.github.com',
port: 443,
path: '/users/octocat',
method: 'GET',
headers: {
'User-Agent': 'Node.js HTTP Client'
}
}

const req = https.request(options, (res) => {
let data = ''

res.on('data', (chunk) => {
data += chunk
})

res.on('end', () => {
console.log('API响应:', JSON.parse(data))
})
})

req.on('error', (err) => {
console.error('请求错误:', err)
})

req.end()

// TCP服务器
const tcpServer = net.createServer((socket) => {
console.log('客户端连接')

socket.on('data', (data) => {
console.log('收到数据:', data.toString())
socket.write('服务器收到: ' + data)
})

socket.on('close', () => {
console.log('客户端断开连接')
})
})

tcpServer.listen(8080, () => {
console.log('TCP服务器运行在端口 8080')
})

6. 错误处理

概念:Node.js提供了多种错误处理机制,包括try-catch、错误事件、回调错误等。

语法规则

  • try-catch:try { } catch (error) { }
  • 错误事件:process.on('uncaughtException', handler)
  • 回调错误:callback(err, data)
  • Promise错误:.catch(error => { })

使用场景

  • 异常捕获
  • 错误日志记录
  • 优雅降级
  • 调试和监控
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// try-catch错误处理
async function riskyOperation() {
try {
const data = await fs.readFile('nonexistent.txt', 'utf8')
return data
} catch (error) {
if (error.code === 'ENOENT') {
console.log('文件不存在,使用默认值')
return 'default content'
} else {
throw error // 重新抛出其他错误
}
}
}

// 全局错误处理
process.on('uncaughtException', (error) => {
console.error('未捕获的异常:', error)
// 记录错误日志
// 优雅关闭应用
process.exit(1)
})

process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的Promise拒绝:', reason)
})

// 自定义错误类
class CustomError extends Error {
constructor(message, code) {
super(message)
this.name = 'CustomError'
this.code = code
}
}

// 错误处理中间件
function errorHandler(err, req, res, next) {
console.error('错误:', err)

if (err instanceof CustomError) {
res.status(400).json({
error: err.message,
code: err.code
})
} else {
res.status(500).json({
error: '服务器内部错误'
})
}
}

// 使用示例
function validateInput(input) {
if (!input) {
throw new CustomError('输入不能为空', 'VALIDATION_ERROR')
}
if (typeof input !== 'string') {
throw new CustomError('输入必须是字符串', 'TYPE_ERROR')
}
return input
}

try {
const result = validateInput('')
} catch (error) {
if (error instanceof CustomError) {
console.log('验证错误:', error.message, error.code)
}
}

Node.js核心模块详解

1. HTTP模块

概念:Node.js内置的HTTP模块用于创建HTTP服务器和客户端。

语法规则

  • 创建服务器:http.createServer()
  • 监听端口:server.listen(port)
  • 发送请求:http.request()
  • 获取请求:http.get()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const http = require('http')
const url = require('url')

// 创建HTTP服务器
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true)
const path = parsedUrl.pathname
const method = req.method

// 设置响应头
res.setHeader('Content-Type', 'application/json')
res.setHeader('Access-Control-Allow-Origin', '*')

// 路由处理
if (path === '/api/users' && method === 'GET') {
res.statusCode = 200
res.end(JSON.stringify({ users: ['张三', '李四'] }))
} else if (path === '/api/users' && method === 'POST') {
let body = ''
req.on('data', chunk => {
body += chunk.toString()
})
req.on('end', () => {
res.statusCode = 201
res.end(JSON.stringify({ message: '用户创建成功', data: JSON.parse(body) }))
})
} else {
res.statusCode = 404
res.end(JSON.stringify({ error: '接口不存在' }))
}
})

server.listen(3000, () => {
console.log('HTTP服务器运行在端口 3000')
})

// HTTP客户端请求
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/users',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}

const req = http.request(options, (res) => {
let data = ''

res.on('data', (chunk) => {
data += chunk
})

res.on('end', () => {
console.log('响应数据:', JSON.parse(data))
})
})

req.on('error', (err) => {
console.error('请求错误:', err)
})

req.end()

2. URL模块

概念:URL模块用于解析和构造URL。

语法规则

  • 解析URL:url.parse(urlString)
  • 构造URL:url.format(urlObject)
  • 解析查询字符串:querystring.parse()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const url = require('url')
const querystring = require('querystring')

// 解析URL
const urlString = 'https://example.com:8080/path?name=张三&age=25#section'
const parsedUrl = url.parse(urlString, true)

console.log('协议:', parsedUrl.protocol) // https:
console.log('主机:', parsedUrl.host) // example.com:8080
console.log('路径:', parsedUrl.pathname) // /path
console.log('查询参数:', parsedUrl.query) // { name: '张三', age: '25' }
console.log('锚点:', parsedUrl.hash) // #section

// 构造URL
const urlObject = {
protocol: 'https:',
host: 'example.com:8080',
pathname: '/api/users',
query: { page: 1, limit: 10 }
}

const constructedUrl = url.format(urlObject)
console.log('构造的URL:', constructedUrl)

// 解析查询字符串
const queryString = 'name=张三&age=25&city=北京'
const parsedQuery = querystring.parse(queryString)
console.log('解析的查询参数:', parsedQuery)

// 构造查询字符串
const queryObject = { name: '张三', age: 25, city: '北京' }
const constructedQuery = querystring.stringify(queryObject)
console.log('构造的查询字符串:', constructedQuery)

3. Crypto模块

概念:Crypto模块提供加密功能,包括哈希、加密、解密等。

语法规则

  • 创建哈希:crypto.createHash(algorithm)
  • 加密:crypto.createCipher()
  • 解密:crypto.createDecipher()
  • 生成随机数:crypto.randomBytes()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const crypto = require('crypto')

// 哈希算法
function createHash(data, algorithm = 'sha256') {
const hash = crypto.createHash(algorithm)
hash.update(data)
return hash.digest('hex')
}

console.log('MD5:', createHash('Hello World', 'md5'))
console.log('SHA256:', createHash('Hello World', 'sha256'))

// 加密和解密
function encrypt(text, secretKey) {
const algorithm = 'aes-256-cbc'
const key = crypto.scryptSync(secretKey, 'salt', 32)
const iv = crypto.randomBytes(16)

const cipher = crypto.createCipher(algorithm, key)
let encrypted = cipher.update(text, 'utf8', 'hex')
encrypted += cipher.final('hex')

return iv.toString('hex') + ':' + encrypted
}

function decrypt(encryptedText, secretKey) {
const algorithm = 'aes-256-cbc'
const key = crypto.scryptSync(secretKey, 'salt', 32)

const textParts = encryptedText.split(':')
const iv = Buffer.from(textParts.shift(), 'hex')
const encrypted = textParts.join(':')

const decipher = crypto.createDecipher(algorithm, key)
let decrypted = decipher.update(encrypted, 'hex', 'utf8')
decrypted += decipher.final('utf8')

return decrypted
}

// 使用示例
const secretKey = 'my-secret-key'
const plainText = 'Hello, World!'

const encrypted = encrypt(plainText, secretKey)
console.log('加密后:', encrypted)

const decrypted = decrypt(encrypted, secretKey)
console.log('解密后:', decrypted)

// 生成随机数
const randomBytes = crypto.randomBytes(16)
console.log('随机字节:', randomBytes.toString('hex'))

// 生成UUID
function generateUUID() {
return crypto.randomUUID()
}

console.log('UUID:', generateUUID())

4. Buffer模块

概念:Buffer是Node.js中用于处理二进制数据的全局对象。

语法规则

  • 创建Buffer:Buffer.from(), Buffer.alloc()
  • 转换:buffer.toString()
  • 操作:buffer.slice(), buffer.copy()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const crypto = require('crypto')

// 创建Buffer
const buf1 = Buffer.from('Hello World', 'utf8')
const buf2 = Buffer.alloc(10)
const buf3 = Buffer.from([1, 2, 3, 4, 5])

console.log('Buffer 1:', buf1)
console.log('Buffer 2:', buf2)
console.log('Buffer 3:', buf3)

// Buffer操作
console.log('长度:', buf1.length)
console.log('转换为字符串:', buf1.toString('utf8'))
console.log('转换为JSON:', buf1.toJSON())

// Buffer拼接
const buf4 = Buffer.from('Hello ')
const buf5 = Buffer.from('World')
const combined = Buffer.concat([buf4, buf5])
console.log('拼接结果:', combined.toString())

// Buffer比较
const buf6 = Buffer.from('Hello')
const buf7 = Buffer.from('Hello')
const buf8 = Buffer.from('World')

console.log('相等比较:', buf6.equals(buf7)) // true
console.log('不相等比较:', buf6.equals(buf8)) // false

// Buffer切片
const sliced = buf1.slice(0, 5)
console.log('切片结果:', sliced.toString())

// Buffer复制
const source = Buffer.from('Hello World')
const target = Buffer.alloc(5)
source.copy(target, 0, 0, 5)
console.log('复制结果:', target.toString())

5. Cluster模块

概念:Cluster模块允许创建共享服务器端口的子进程,充分利用多核CPU。

语法规则

  • 创建集群:cluster.fork()
  • 监听事件:cluster.on('fork', callback)
  • 检查进程:cluster.isMaster
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const cluster = require('cluster')
const numCPUs = require('os').cpus().length

if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`)

// 创建工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}

cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`)
// 重启工作进程
cluster.fork()
})

cluster.on('online', (worker) => {
console.log(`工作进程 ${worker.process.pid} 已上线`)
})

} else {
// 工作进程
const express = require('express')
const app = express()

app.get('/', (req, res) => {
res.json({
message: 'Hello from worker',
pid: process.pid,
timestamp: new Date().toISOString()
})
})

app.listen(3000, () => {
console.log(`工作进程 ${process.pid} 监听端口 3000`)
})
}

6. OS模块

概念:OS模块提供操作系统相关的实用方法。

语法规则

  • 获取系统信息:os.platform(), os.arch()
  • 获取内存信息:os.totalmem(), os.freemem()
  • 获取CPU信息:os.cpus()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const os = require('os')

// 系统信息
console.log('操作系统:', os.platform())
console.log('架构:', os.arch())
console.log('主机名:', os.hostname())
console.log('系统类型:', os.type())
console.log('系统版本:', os.release())

// 内存信息
console.log('总内存:', Math.round(os.totalmem() / 1024 / 1024 / 1024), 'GB')
console.log('空闲内存:', Math.round(os.freemem() / 1024 / 1024 / 1024), 'GB')
console.log('内存使用率:', Math.round((1 - os.freemem() / os.totalmem()) * 100), '%')

// CPU信息
const cpus = os.cpus()
console.log('CPU核心数:', cpus.length)
console.log('CPU型号:', cpus[0].model)
console.log('CPU速度:', cpus[0].speed, 'MHz')

// 网络接口
const networkInterfaces = os.networkInterfaces()
console.log('网络接口:', Object.keys(networkInterfaces))

// 用户信息
console.log('用户信息:', os.userInfo())
console.log('临时目录:', os.tmpdir())
console.log('主目录:', os.homedir())

// 系统运行时间
console.log('系统运行时间:', Math.round(os.uptime() / 3600), '小时')

7. Util模块

概念:Util模块提供实用工具函数。

语法规则

  • 回调转Promise:util.promisify()
  • 继承:util.inherits()
  • 调试:util.inspect()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
const util = require('util')
const fs = require('fs')

// 回调转Promise
const readFile = util.promisify(fs.readFile)
const writeFile = util.promisify(fs.writeFile)

// 使用Promise化的函数
async function fileOperations() {
try {
const data = await readFile('package.json', 'utf8')
console.log('文件内容:', data)

await writeFile('output.txt', 'Hello, World!')
console.log('文件写入成功')
} catch (error) {
console.error('文件操作错误:', error)
}
}

fileOperations()

// 继承
function BaseClass() {
this.name = 'Base'
}

BaseClass.prototype.sayHello = function() {
console.log(`Hello from ${this.name}`)
}

function DerivedClass() {
BaseClass.call(this)
this.name = 'Derived'
}

util.inherits(DerivedClass, BaseClass)

const instance = new DerivedClass()
instance.sayHello() // Hello from Derived

// 调试输出
const obj = {
name: '张三',
age: 25,
hobbies: ['读书', '游泳', '编程'],
address: {
city: '北京',
district: '朝阳区'
}
}

console.log('调试输出:', util.inspect(obj, {
colors: true,
depth: 2,
showHidden: false
}))

// 格式化字符串
const formatted = util.format('用户 %s 今年 %d 岁', '张三', 25)
console.log('格式化字符串:', formatted)

// 检查类型
console.log('是否为数组:', util.isArray([1, 2, 3]))
console.log('是否为日期:', util.isDate(new Date()))
console.log('是否为错误:', util.isError(new Error('测试错误')))

8. Events模块

概念:Events模块是Node.js事件驱动架构的核心。

语法规则

  • 创建事件发射器:new EventEmitter()
  • 监听事件:emitter.on(), emitter.once()
  • 发射事件:emitter.emit()
  • 移除监听器:emitter.removeListener()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const EventEmitter = require('events')

// 自定义事件发射器
class MyEmitter extends EventEmitter {
constructor() {
super()
this.maxListeners = 10
}

// 自定义方法
start() {
this.emit('start', { timestamp: new Date() })
}

stop() {
this.emit('stop', { timestamp: new Date() })
}
}

const myEmitter = new MyEmitter()

// 监听事件
myEmitter.on('start', (data) => {
console.log('开始事件:', data)
})

myEmitter.once('stop', (data) => {
console.log('停止事件 (只执行一次):', data)
})

// 监听错误事件
myEmitter.on('error', (err) => {
console.error('错误事件:', err.message)
})

// 发射事件
myEmitter.start()
myEmitter.start() // 会再次触发
myEmitter.stop()
myEmitter.stop() // 不会触发,因为使用了once

// 错误处理
myEmitter.emit('error', new Error('Something went wrong!'))

// 获取监听器信息
console.log('start事件监听器数量:', myEmitter.listenerCount('start'))
console.log('所有事件名称:', myEmitter.eventNames())

// 移除监听器
myEmitter.removeAllListeners('start')
console.log('移除后start事件监听器数量:', myEmitter.listenerCount('start'))

9. 数据库集成

概念:Node.js可以与各种数据库集成,包括MySQL、MongoDB、PostgreSQL等。

MongoDB集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const { MongoClient } = require('mongodb')

async function connectToMongoDB() {
const client = new MongoClient('mongodb://localhost:27017')

try {
await client.connect()
console.log('连接到MongoDB成功')

const db = client.db('mydb')
const collection = db.collection('users')

// 插入文档
const insertResult = await collection.insertOne({
name: '张三',
email: 'zhangsan@example.com',
age: 25,
createdAt: new Date()
})
console.log('插入结果:', insertResult.insertedId)

// 查询文档
const users = await collection.find({ age: { $gte: 18 } }).toArray()
console.log('查询结果:', users)

// 更新文档
const updateResult = await collection.updateOne(
{ name: '张三' },
{ $set: { age: 26 } }
)
console.log('更新结果:', updateResult.modifiedCount)

// 删除文档
const deleteResult = await collection.deleteOne({ name: '张三' })
console.log('删除结果:', deleteResult.deletedCount)

} catch (error) {
console.error('MongoDB操作错误:', error)
} finally {
await client.close()
}
}

connectToMongoDB()

MySQL集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const mysql = require('mysql2/promise')

async function connectToMySQL() {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb'
})

try {
console.log('连接到MySQL成功')

// 创建表
await connection.execute(`
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`)

// 插入数据
const [insertResult] = await connection.execute(
'INSERT INTO users (name, email, age) VALUES (?, ?, ?)',
['张三', 'zhangsan@example.com', 25]
)
console.log('插入结果:', insertResult.insertId)

// 查询数据
const [rows] = await connection.execute(
'SELECT * FROM users WHERE age >= ?',
[18]
)
console.log('查询结果:', rows)

// 更新数据
const [updateResult] = await connection.execute(
'UPDATE users SET age = ? WHERE name = ?',
[26, '张三']
)
console.log('更新结果:', updateResult.affectedRows)

// 删除数据
const [deleteResult] = await connection.execute(
'DELETE FROM users WHERE name = ?',
['张三']
)
console.log('删除结果:', deleteResult.affectedRows)

} catch (error) {
console.error('MySQL操作错误:', error)
} finally {
await connection.end()
}
}

connectToMySQL()

10. 性能优化

概念:Node.js性能优化包括内存管理、CPU优化、I/O优化等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
const cluster = require('cluster')
const os = require('os')

// 1. 集群模式优化
if (cluster.isMaster) {
const numCPUs = os.cpus().length

for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}

cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 退出`)
cluster.fork() // 重启工作进程
})
} else {
// 2. 内存优化
const v8 = require('v8')

// 设置内存限制
v8.setFlagsFromString('--max-old-space-size=4096')

// 监控内存使用
setInterval(() => {
const memUsage = process.memoryUsage()
console.log('内存使用:', {
rss: Math.round(memUsage.rss / 1024 / 1024) + ' MB',
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024) + ' MB',
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024) + ' MB',
external: Math.round(memUsage.external / 1024 / 1024) + ' MB'
})
}, 5000)

// 3. 垃圾回收优化
if (global.gc) {
setInterval(() => {
global.gc()
console.log('手动垃圾回收完成')
}, 30000)
}

// 4. 缓存优化
const NodeCache = require('node-cache')
const cache = new NodeCache({ stdTTL: 600 }) // 10分钟过期

function getCachedData(key) {
let data = cache.get(key)
if (!data) {
// 模拟从数据库获取数据
data = { id: key, value: Math.random(), timestamp: new Date() }
cache.set(key, data)
console.log('数据已缓存')
} else {
console.log('从缓存获取数据')
}
return data
}

// 5. 连接池优化
const mysql = require('mysql2/promise')

const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})

async function queryWithPool(sql, params) {
const connection = await pool.getConnection()
try {
const [rows] = await connection.execute(sql, params)
return rows
} finally {
connection.release()
}
}

// 6. 压缩优化
const compression = require('compression')
const express = require('express')

const app = express()
app.use(compression())

app.get('/api/data', (req, res) => {
const data = Array.from({ length: 1000 }, (_, i) => ({
id: i,
name: `用户${i}`,
email: `user${i}@example.com`
}))

res.json(data)
})

app.listen(3000, () => {
console.log(`工作进程 ${process.pid} 监听端口 3000`)
})
}

Node.js Web框架

1. Express框架

概念:Express是Node.js最流行的Web应用框架,提供了简洁的API来构建Web应用和API。

语法规则

  • 安装:npm install express
  • 创建应用:const app = express()
  • 路由:app.get(), app.post(), app.put(), app.delete()
  • 中间件:app.use()
  • 启动服务器:app.listen(port)

使用场景

  • RESTful API开发
  • Web应用后端
  • 微服务架构
  • 快速原型开发

Express基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
const express = require('express')
const app = express()

// 中间件:解析JSON请求体
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

// 静态文件服务
app.use(express.static('public'))

// 基本路由
app.get('/', (req, res) => {
res.send('<h1>Hello, Express!</h1>')
})

app.get('/api/users', (req, res) => {
const users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
]
res.json(users)
})

app.get('/api/users/:id', (req, res) => {
const userId = parseInt(req.params.id)
const user = { id: userId, name: '张三', email: 'zhangsan@example.com' }
res.json(user)
})

app.post('/api/users', (req, res) => {
const { name, email } = req.body
const newUser = {
id: Date.now(),
name,
email
}
res.status(201).json(newUser)
})

// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).json({ error: '服务器内部错误' })
})

// 404处理
app.use((req, res) => {
res.status(404).json({ error: '页面未找到' })
})

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Express服务器运行在 http://localhost:${PORT}`)
})

Express中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const express = require('express')
const app = express()

// 自定义中间件:请求日志
function requestLogger(req, res, next) {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`)
next()
}

// 自定义中间件:CORS处理
function corsHandler(req, res, next) {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
next()
}

// 自定义中间件:身份验证
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[1]

if (!token) {
return res.status(401).json({ error: '访问令牌缺失' })
}

// 这里应该验证JWT token
// 简化示例
if (token === 'valid-token') {
req.user = { id: 1, name: '张三' }
next()
} else {
res.status(403).json({ error: '无效的访问令牌' })
}
}

// 应用中间件
app.use(requestLogger)
app.use(corsHandler)
app.use(express.json())

// 受保护的路由
app.get('/api/profile', authenticateToken, (req, res) => {
res.json({ user: req.user })
})

// 路由级中间件
app.get('/api/admin', authenticateToken, (req, res, next) => {
if (req.user.id !== 1) {
return res.status(403).json({ error: '权限不足' })
}
next()
}, (req, res) => {
res.json({ message: '管理员页面' })
})

Express路由模块化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// routes/users.js
const express = require('express')
const router = express.Router()

// 模拟用户数据
let users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
]

// GET /users
router.get('/', (req, res) => {
res.json(users)
})

// GET /users/:id
router.get('/:id', (req, res) => {
const userId = parseInt(req.params.id)
const user = users.find(u => u.id === userId)

if (!user) {
return res.status(404).json({ error: '用户未找到' })
}

res.json(user)
})

// POST /users
router.post('/', (req, res) => {
const { name, email } = req.body

if (!name || !email) {
return res.status(400).json({ error: '姓名和邮箱是必需的' })
}

const newUser = {
id: users.length + 1,
name,
email
}

users.push(newUser)
res.status(201).json(newUser)
})

// PUT /users/:id
router.put('/:id', (req, res) => {
const userId = parseInt(req.params.id)
const userIndex = users.findIndex(u => u.id === userId)

if (userIndex === -1) {
return res.status(404).json({ error: '用户未找到' })
}

const { name, email } = req.body
users[userIndex] = { ...users[userIndex], name, email }

res.json(users[userIndex])
})

// DELETE /users/:id
router.delete('/:id', (req, res) => {
const userId = parseInt(req.params.id)
const userIndex = users.findIndex(u => u.id === userId)

if (userIndex === -1) {
return res.status(404).json({ error: '用户未找到' })
}

users.splice(userIndex, 1)
res.status(204).send()
})

module.exports = router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// app.js - 主应用文件
const express = require('express')
const userRoutes = require('./routes/users')

const app = express()

// 中间件
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

// 路由
app.use('/api/users', userRoutes)

// 根路由
app.get('/', (req, res) => {
res.json({ message: '用户管理API' })
})

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`)
})

2. Koa框架

概念:Koa是Express团队开发的下一代Web框架,使用async/await语法,更加轻量和灵活。

语法规则

  • 安装:npm install koa
  • 创建应用:const app = new Koa()
  • 中间件:app.use()
  • 上下文:ctx对象包含request和response
  • 启动服务器:app.listen(port)

使用场景

  • 现代Web应用
  • API服务
  • 微服务架构
  • 需要更好的错误处理

Koa基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const Koa = require('koa')
const Router = require('@koa/router')
const bodyParser = require('koa-bodyparser')
const cors = require('@koa/cors')

const app = new Koa()
const router = new Router()

// 中间件
app.use(cors())
app.use(bodyParser())

// 基本路由
router.get('/', (ctx) => {
ctx.body = '<h1>Hello, Koa!</h1>'
})

router.get('/api/users', (ctx) => {
const users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
]
ctx.body = users
})

router.get('/api/users/:id', (ctx) => {
const userId = parseInt(ctx.params.id)
const user = { id: userId, name: '张三', email: 'zhangsan@example.com' }
ctx.body = user
})

router.post('/api/users', (ctx) => {
const { name, email } = ctx.request.body
const newUser = {
id: Date.now(),
name,
email
}
ctx.status = 201
ctx.body = newUser
})

// 应用路由
app.use(router.routes())
app.use(router.allowedMethods())

// 错误处理
app.on('error', (err, ctx) => {
console.error('服务器错误:', err)
})

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Koa服务器运行在 http://localhost:${PORT}`)
})

Koa中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const Koa = require('koa')
const app = new Koa()

// 自定义中间件:请求日志
async function requestLogger(ctx, next) {
const start = Date.now()
console.log(`${new Date().toISOString()} - ${ctx.method} ${ctx.url}`)

await next()

const ms = Date.now() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
}

// 自定义中间件:响应时间
async function responseTime(ctx, next) {
const start = Date.now()
await next()
const ms = Date.now() - start
ctx.set('X-Response-Time', `${ms}ms`)
}

// 自定义中间件:身份验证
async function authenticate(ctx, next) {
const token = ctx.headers.authorization?.split(' ')[1]

if (!token) {
ctx.status = 401
ctx.body = { error: '访问令牌缺失' }
return
}

// 简化验证
if (token === 'valid-token') {
ctx.state.user = { id: 1, name: '张三' }
await next()
} else {
ctx.status = 403
ctx.body = { error: '无效的访问令牌' }
}
}

// 应用中间件
app.use(responseTime)
app.use(requestLogger)

// 路由
app.use(async (ctx) => {
if (ctx.path === '/') {
ctx.body = '<h1>Hello, Koa!</h1>'
} else if (ctx.path === '/api/profile') {
await authenticate(ctx, async () => {
ctx.body = { user: ctx.state.user }
})
} else {
ctx.status = 404
ctx.body = { error: '页面未找到' }
}
})

Koa vs Express对比

特性 Express Koa
语法 回调函数 async/await
中间件 线性执行 洋葱模型
错误处理 需要额外配置 内置try-catch
学习曲线 相对简单 需要理解async/await
生态系统 非常丰富 相对较少
性能 良好 更好
灵活性 更高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Express中间件执行顺序
app.use(middleware1) // 1
app.use(middleware2) // 2
app.get('/api', handler) // 3

// 执行顺序: middleware1 -> middleware2 -> handler

// Koa中间件执行顺序(洋葱模型)
app.use(async (ctx, next) => {
console.log('1. 开始')
await next()
console.log('1. 结束')
})

app.use(async (ctx, next) => {
console.log('2. 开始')
await next()
console.log('2. 结束')
})

app.use(async (ctx) => {
console.log('3. 处理')
ctx.body = 'Hello'
})

// 执行顺序: 1. 开始 -> 2. 开始 -> 3. 处理 -> 2. 结束 -> 1. 结束

3. 常用中间件

概念:中间件是处理请求和响应的函数,可以执行各种任务如身份验证、日志记录、错误处理等。

常用中间件

  • cors - 跨域资源共享
  • helmet - 安全头设置
  • morgan - HTTP请求日志
  • compression - 响应压缩
  • rate-limiter - 请求频率限制

Express常用中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const express = require('express')
const cors = require('cors')
const helmet = require('helmet')
const morgan = require('morgan')
const compression = require('compression')
const rateLimit = require('express-rate-limit')

const app = express()

// 安全中间件
app.use(helmet())

// CORS中间件
app.use(cors({
origin: ['http://localhost:3000', 'https://yourdomain.com'],
credentials: true
}))

// 日志中间件
app.use(morgan('combined'))

// 压缩中间件
app.use(compression())

// 请求频率限制
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 15分钟内最多100个请求
message: '请求过于频繁,请稍后再试'
})
app.use('/api/', limiter)

// 解析中间件
app.use(express.json({ limit: '10mb' }))
app.use(express.urlencoded({ extended: true, limit: '10mb' }))

// 静态文件服务
app.use(express.static('public'))

// 路由
app.get('/api/test', (req, res) => {
res.json({ message: '测试成功' })
})

app.listen(3000, () => {
console.log('服务器运行在端口 3000')
})

Koa常用中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const Koa = require('koa')
const Router = require('@koa/router')
const bodyParser = require('koa-bodyparser')
const cors = require('@koa/cors')
const helmet = require('koa-helmet')
const logger = require('koa-logger')
const compress = require('koa-compress')
const ratelimit = require('koa-ratelimit')

const app = new Koa()
const router = new Router()

// 安全中间件
app.use(helmet())

// CORS中间件
app.use(cors({
origin: ['http://localhost:3000', 'https://yourdomain.com'],
credentials: true
}))

// 日志中间件
app.use(logger())

// 压缩中间件
app.use(compress())

// 请求频率限制
app.use(ratelimit({
driver: 'memory',
db: new Map(),
duration: 60000, // 1分钟
errorMessage: '请求过于频繁',
id: (ctx) => ctx.ip,
headers: {
remaining: 'Rate-Limit-Remaining',
reset: 'Rate-Limit-Reset',
total: 'Rate-Limit-Total'
},
max: 100 // 每分钟最多100个请求
}))

// 解析中间件
app.use(bodyParser({
jsonLimit: '10mb',
formLimit: '10mb'
}))

// 路由
router.get('/api/test', (ctx) => {
ctx.body = { message: '测试成功' }
})

app.use(router.routes())
app.use(router.allowedMethods())

app.listen(3000, () => {
console.log('服务器运行在端口 3000')
})