下面是一个完整的指南,教你如何从零开始构建一个Node.js服务来托管前端项目,并代理API请求到其他服务器。
1. 项目初始化
# 创建项目目录
mkdir node-proxy-server
cd node-proxy-server
# 初始化npm项目
npm init -y
# 安装必要依赖
npm install express http-proxy-middleware compression cors morgan
npm install nodemon --save-dev
2. 基础服务器配置
创建 server.js
文件:
const express = require('express')
const path = require('path')
const { createProxyMiddleware } = require('http-proxy-middleware')
const compression = require('compression')
const cors = require('cors')
const morgan = require('morgan')
const app = express()
const PORT = process.env.PORT || 3000
// 中间件配置
app.use(compression()) // 启用gzip压缩
app.use(cors()) // 跨域支持
app.use(morgan('dev')) // 请求日志
// 静态文件服务 - 托管前端构建产物
app.use(express.static(path.join(__dirname, 'dist')))
// API代理配置
const apiProxy = createProxyMiddleware({
target: 'http://api.your-backend.com', // 你的后端API地址
changeOrigin: true,
pathRewrite: {
'^/api': '' // 移除/api前缀
},
onProxyReq: (proxyReq, req, res) => {
// 可以在这里添加请求头等操作
console.log(`代理请求: ${req.method} ${req.path} -> ${proxyReq.path}`)
},
onError: (err, req, res) => {
console.error('代理错误:', err)
res.status(500).json({ error: '代理请求失败' })
}
})
// 应用代理中间件
app.use('/api', apiProxy)
// 处理前端路由 - 所有未匹配的请求返回index.html
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`)
console.log(`代理API请求到: http://api.your-backend.com`)
})
3. 前端项目构建与部署
假设你有一个Vue/React前端项目:
- 构建前端项目:
# 在Vue项目中
npm run build
# 或React项目中
npm run build
- 将构建产物复制到Node.js项目:
# 从Vue项目
cp -R your-vue-project/dist ./node-proxy-server/
# 或从React项目
cp -R your-react-project/build ./node-proxy-server/dist
4. 环境变量配置
创建 .env
文件:
PORT=3000
API_BASE_URL=http://api.your-backend.com
NODE_ENV=production
修改 server.js
使用环境变量:
require('dotenv').config()
// 更新代理配置
const apiProxy = createProxyMiddleware({
target: process.env.API_BASE_URL || 'http://api.your-backend.com',
// ...其他配置不变
})
5. 高级代理配置
多API端点代理
// 用户服务
app.use('/api/user', createProxyMiddleware({
target: 'http://user-service.your-backend.com',
changeOrigin: true,
pathRewrite: { '^/api/user': '' }
}))
// 订单服务
app.use('/api/order', createProxyMiddleware({
target: 'http://order-service.your-backend.com',
changeOrigin: true,
pathRewrite: { '^/api/order': '' }
}))
WebSocket代理
const wsProxy = createProxyMiddleware('/ws', {
target: 'ws://your-websocket-server.com',
ws: true,
changeOrigin: true,
logLevel: 'debug'
})
app.use(wsProxy)
6. 安全增强
const helmet = require('helmet')
// 添加安全头
app.use(helmet())
// 限制请求体大小
app.use(express.json({ limit: '10kb' }))
app.use(express.urlencoded({ extended: true, limit: '10kb' }))
// 速率限制
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 每个IP限制100个请求
})
app.use(limiter)
7. 开发与生产配置
package.json脚本
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
}
开发模式热重载
if (process.env.NODE_ENV === 'development') {
const chokidar = require('chokidar')
const watcher = chokidar.watch('./dist')
watcher.on('ready', () => {
watcher.on('all', () => {
console.log('检测到前端文件变化,清除模块缓存...')
Object.keys(require.cache).forEach(id => {
if (id.includes('/dist/')) delete require.cache[id]
})
})
})
}
8. 完整项目结构
node-proxy-server/
├── dist/ # 前端构建产物
│ ├── index.html
│ ├── static/
│ └── ...
├── server.js # 主服务器文件
├── .env # 环境变量
├── .gitignore
└── package.json
9. 部署指南
PM2生产环境部署
npm install pm2 -g
pm2 start server.js --name "node-proxy"
pm2 save
pm2 startup
Docker部署
创建 Dockerfile
:
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
ENV PORT=3000
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "server.js"]
构建并运行:
docker build -t node-proxy .
docker run -d -p 3000:3000 --name node-proxy node-proxy
10. 测试与验证
- 启动服务器:
npm run dev
验证静态文件服务:
访问http://localhost:3000
应该看到你的前端应用验证API代理:
访问http://localhost:3000/api/some-endpoint
应该代理到你的后端服务验证前端路由:
刷新非根路由(如http://localhost:3000/about
)应该正确返回index.html
常见问题解决
代理不工作:
- 检查目标服务器是否可访问
- 检查代理路径配置是否正确
- 查看服务器日志中的错误信息
前端路由问题:
- 确保所有路由都返回index.html
- 检查前端路由模式(history vs hash)
跨域问题:
- 确保正确配置了CORS中间件
- 检查代理是否正确地修改了Origin头
这个Node.js代理服务器提供了完整的解决方案,包括:
- 静态文件服务
- API请求代理
- 开发与生产环境支持
- 安全增强
- 部署选项
你可以根据实际需求进一步定制和扩展这个基础架构。