在一台服务器上同时部署前端React应用和Node.js后端服务是一个常见需求。以下是详细的部署方案:
1. 项目结构建议
/server
├── app.js (或 server.js)
├── routes/
├── controllers/
└── package.json
/client
├── public/
├── src/
└── package.json
package.json (根目录,用于统一管理)
2. 前端构建配置
React应用构建
# 构建生产版本
npm run build
构建后的文件会生成在 client/build 目录。
3. 后端服务配置
Express服务器示例
// server/app.js
const express = require('express');
const path = require('path');
const app = express();
// 静态文件服务 - 前端
app.use(express.static(path.join(__dirname, '../client/build')));
// API路由
app.use('/api', require('./routes/api'));
// 处理所有其他请求,返回index.html
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../client/build', 'index.html'));
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
4. 跨域解决方案
开发环境(CORS)
// server/app.js
const cors = require('cors');
// 允许前端访问
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
生产环境(反向)
# Nginx配置
server {
listen 80;
server_name your-domain.com;
# 前端静态文件
location / {
root /var/www/your-app/client/build;
try_files $uri $uri/ /index.html;
}
# API到Node.js
location /api {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
5. 环境变量管理
.env文件
# .env
NODE_ENV=production
PORT=5000
DATABASE_URL=mongodb://localhost:27017/myapp
API_BASE_URL=/api
FRONTEND_BUILD_PATH=../client/build
在代码中使用
// server/config.js
require('dotenv').config();
module.exports = {
port: process.env.PORT || 5000,
dbUrl: process.env.DATABASE_URL,
env: process.env.NODE_ENV
};
6. 启动脚本配置
package.json
{
"scripts": {
"build": "cd client && npm run build",
"start": "node server/app.js",
"dev": "concurrently "cd server && nodemon app.js" "cd client && npm start"",
"prod": "npm run build && npm run start"
},
"dependencies": {
"express": "^4.18.0",
"dotenv": "^16.0.0"
},
"devDependencies": {
"concurrently": "^7.0.0"
}
}
7. 进程管理
使用PM2管理进程
# 安装PM2
npm install -g pm2
# 启动应用
pm2 start server/app.js --name "my-app"
# 设置开机自启
pm2 startup
pm2 save
# 查看状态
pm2 status
pm2 logs
PM2配置文件
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'my-app',
script: './server/app.js',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
};
8. Docker部署方案
Dockerfile
FROM node:16-alpine
WORKDIR /app
# 安装依赖
COPY package*.json ./
RUN npm ci --only=production
# 复制前端构建文件
COPY client/build ./client/build
# 复制服务器文件
COPY server ./server
# 暴露端口
EXPOSE 5000
# 启动命令
CMD ["node", "server/app.js"]
docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "5000:5000"
environment:
- NODE_ENV=production
volumes:
- ./logs:/app/logs
restart: unless-stopped
9. 安全最佳实践
HTTPS配置
// server/https-server.js
const https = require('https');
const fs = require('fs');
const express = require('express');
const options = {
key: fs.readFileSync('/path/to/private.key'),
cert: fs.readFileSync('/path/to/certificate.crt')
};
const app = express();
// ... 应用配置
https.createServer(options, app).listen(443);
安全中间件
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
app.use(helmet());
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 限制每个IP 100次请求
}));
10. 监控和日志
// 日志中间件
const morgan = require('morgan');
const winston = require('winston');
// 请求日志
app.use(morgan('combined'));
// 错误处理
app.use((err, req, res, next) => {
winston.error(err.stack);
res.status(500).send('Something broke!');
});
部署流程总结
- 准备阶段:确保服务器环境配置好Node.js、Nginx等
- 构建前端:
npm run build生成生产版本 - 启动后端:使用PM2启动Node.js服务
- 配置反向:使用Nginx处理静态文件和API请求
- 设置SSL:配置HTTPS证书
- 监控维护:设置日志监控和错误报警
这样部署既保证了性能,又实现了前后端的合理分离和集成。
CLOUD技术笔记