Next.js 自定义服务器 🖥️
🎯 概述
虽然 Next.js 内置服务器已经很强大,但有时需要自定义服务器来实现特殊需求。
📦 基本设置
创建服务器
js
// server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer(async (req, res) => {
try {
const parsedUrl = parse(req.url, true)
await handle(req, res, parsedUrl)
} catch (err) {
console.error('Error occurred handling', req.url, err)
res.statusCode = 500
res.end('internal server error')
}
}).listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://${hostname}:${port}`)
})
})package.json
json
{
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
}
}🚀 Express 集成
js
// server.js
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
// 自定义路由
server.get('/api/custom', (req, res) => {
res.json({ message: 'Custom API' })
})
// 所有其他请求交给 Next.js
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})📝 WebSocket 支持
js
// server.js
const { createServer } = require('http')
const { Server } = require('socket.io')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = createServer((req, res) => {
handle(req, res)
})
const io = new Server(server)
io.on('connection', (socket) => {
console.log('Client connected')
socket.on('message', (data) => {
io.emit('message', data)
})
socket.on('disconnect', () => {
console.log('Client disconnected')
})
})
server.listen(3000)
})🎨 中间件
js
// server.js
const express = require('express')
const next = require('next')
const compression = require('compression')
const helmet = require('helmet')
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
// 安全头部
server.use(helmet())
// Gzip 压缩
server.use(compression())
// 日志
server.use((req, res, next) => {
console.log(`${req.method} ${req.url}`)
next()
})
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(3000)
})📚 最佳实践
1. 错误处理
js
server.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})2. 性能监控
js
server.use((req, res, next) => {
const start = Date.now()
res.on('finish', () => {
const duration = Date.now() - start
console.log(`${req.method} ${req.url} - ${duration}ms`)
})
next()
})3. 限制
⚠️ 使用自定义服务器会失去:
- 自动静态优化
- Serverless 函数
- 某些 Vercel 功能
🔗 相关资源
下一步:学习 Next.js 环境变量。