主题
Node.js 网络与 HTTP
Node.js 内置 http 模块即可构建 Web 服务,理解原生 HTTP 编程有助于掌握 Express / Koa / NestJS 等框架的底层原理。
作者:yanshaodong
创建 HTTP 服务
javascript
const http = require('http')
const server = http.createServer((req, res) => {
// req:可读流,包含请求行/头/体
// res:可写流,用于返回响应
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('Hello')
})
server.listen(3000, () => console.log('listening on 3000'))请求对象(req)
javascript
const { URL } = require('url')
server.on('request', (req, res) => {
const url = new URL(req.url, 'http://' + req.headers.host)
console.log(req.method) // GET / POST ...
console.log(url.pathname) // /api/users
console.log(req.headers) // 请求头对象
// 读取请求体(流式)
let body = ''
req.on('data', (chunk) => { body += chunk })
req.on('end', () => {
console.log('body:', body)
})
})响应对象(res)
javascript
res.statusCode = 201
res.setHeader('Content-Type', 'application/json')
res.write(JSON.stringify({ ok: true }))
res.end() // 结束响应(必须调用)
// 或一次性
res.writeHead(404, { 'Content-Type': 'text/plain' })
res.end('Not Found')路由分发
javascript
const server = http.createServer((req, res) => {
const { pathname } = new URL(req.url, 'http://localhost')
if (req.method === 'GET' && pathname === '/api/users') {
res.end(JSON.stringify([{ id: 1, name: 'Tom' }]))
} else if (req.method === 'POST' && pathname === '/api/users') {
// 处理创建
res.end('created')
} else {
res.statusCode = 404
res.end('Not Found')
}
})静态文件服务
javascript
const fs = require('fs')
const path = require('path')
const mime = require('mime-types') // npm i mime-types
server.on('request', (req, res) => {
const filePath = path.join(__dirname, 'public', req.url)
fs.createReadStream(filePath)
.on('error', () => { res.statusCode = 404; res.end('404') })
.pipe(res)
})中间件雏形
框架的"中间件"本质是对 req/res 的链式处理函数。
javascript
const middlewares = []
function use(fn) { middlewares.push(fn) }
use((req, res, next) => {
req.start = Date.now()
next()
})
use((req, res, next) => {
console.log('耗时:', Date.now() - req.start)
next()
})
function handle(req, res) {
let i = 0
const next = () => {
const fn = middlewares[i++]
fn ? fn(req, res, next) : res.end('done')
}
next()
}这正是 Express/Koa 的设计思想:把通用逻辑(日志、鉴权、错误处理)拆成可复用的中间件。
HTTPS 服务
javascript
const https = require('https')
const fs = require('fs')
const options = {
key: fs.readFileSync('privkey.pem'),
cert: fs.readFileSync('fullchain.pem')
}
https.createServer(options, (req, res) => {
res.end('secure')
}).listen(443)客户端请求
javascript
const https = require('https')
https.get('https://api.example.com/data', (res) => {
let data = ''
res.on('data', (c) => (data += c))
res.on('end', () => console.log(JSON.parse(data)))
})实际项目中建议直接使用
fetch(Node 18+ 内置)、axios或undici,而非手写http.request。
作者:yanshaodong