mirror of
https://github.com/patdelphi/suanming.git
synced 2026-02-28 05:33:11 +08:00
添加Railway部署配置文件和CORS设置
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -47,4 +47,10 @@ temp/
|
|||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# Database files (SQLite)
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
numerology.db*
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
# Vercel 部署指南
|
|
||||||
|
|
||||||
本指南将帮助您将三算命项目部署到 Vercel 平台。
|
|
||||||
|
|
||||||
## 🚀 快速部署
|
|
||||||
|
|
||||||
### 1. 准备工作
|
|
||||||
|
|
||||||
确保您的项目已推送到 GitHub:
|
|
||||||
```bash
|
|
||||||
git add .
|
|
||||||
git commit -m "准备Vercel部署"
|
|
||||||
git push origin master
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 连接 Vercel
|
|
||||||
|
|
||||||
1. 访问 [vercel.com](https://vercel.com)
|
|
||||||
2. 使用 GitHub 账号登录
|
|
||||||
3. 点击 "New Project"
|
|
||||||
4. 选择您的 `suanming` 仓库
|
|
||||||
5. 点击 "Import"
|
|
||||||
|
|
||||||
### 3. 配置环境变量
|
|
||||||
|
|
||||||
在 Vercel 项目设置中添加以下环境变量:
|
|
||||||
|
|
||||||
```
|
|
||||||
NODE_ENV=production
|
|
||||||
JWT_SECRET=your_secure_jwt_secret_here
|
|
||||||
CORS_ORIGIN=https://your-app-name.vercel.app
|
|
||||||
```
|
|
||||||
|
|
||||||
**生成 JWT Secret:**
|
|
||||||
```bash
|
|
||||||
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 数据库配置
|
|
||||||
|
|
||||||
由于 Vercel 不支持 SQLite 文件存储,您需要迁移到云数据库:
|
|
||||||
|
|
||||||
#### 选项 1: Vercel Postgres(推荐)
|
|
||||||
1. 在 Vercel 项目中添加 Postgres 数据库
|
|
||||||
2. 复制连接字符串到环境变量 `DATABASE_URL`
|
|
||||||
3. 修改数据库连接代码
|
|
||||||
|
|
||||||
#### 选项 2: PlanetScale
|
|
||||||
1. 注册 [PlanetScale](https://planetscale.com)
|
|
||||||
2. 创建数据库
|
|
||||||
3. 获取连接字符串
|
|
||||||
4. 添加到环境变量 `DATABASE_URL`
|
|
||||||
|
|
||||||
### 5. 部署
|
|
||||||
|
|
||||||
配置完成后,Vercel 会自动部署您的应用。
|
|
||||||
|
|
||||||
## 📁 项目结构说明
|
|
||||||
|
|
||||||
```
|
|
||||||
├── vercel.json # Vercel 配置文件
|
|
||||||
├── .env.production # 生产环境变量模板
|
|
||||||
├── src/ # 前端代码
|
|
||||||
└── server/ # 后端 API
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 配置文件说明
|
|
||||||
|
|
||||||
### vercel.json
|
|
||||||
- 配置构建和路由规则
|
|
||||||
- 将 `/api/*` 路由到后端服务
|
|
||||||
- 其他路由指向前端应用
|
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
- `NODE_ENV`: 设置为 production
|
|
||||||
- `JWT_SECRET`: JWT 令牌密钥
|
|
||||||
- `CORS_ORIGIN`: 允许的跨域来源
|
|
||||||
- `DATABASE_URL`: 数据库连接字符串(如使用云数据库)
|
|
||||||
|
|
||||||
## 🗄️ 数据库迁移
|
|
||||||
|
|
||||||
如果您选择使用云数据库,需要执行以下步骤:
|
|
||||||
|
|
||||||
### 1. 修改数据库连接
|
|
||||||
|
|
||||||
编辑 `server/database/index.cjs`:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 替换 SQLite 连接为 PostgreSQL
|
|
||||||
const { Pool } = require('pg');
|
|
||||||
|
|
||||||
const pool = new Pool({
|
|
||||||
connectionString: process.env.DATABASE_URL,
|
|
||||||
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 更新 SQL 语法
|
|
||||||
|
|
||||||
将 SQLite 语法转换为 PostgreSQL 语法:
|
|
||||||
- `INTEGER PRIMARY KEY AUTOINCREMENT` → `SERIAL PRIMARY KEY`
|
|
||||||
- `TEXT` → `VARCHAR` 或 `TEXT`
|
|
||||||
- 日期时间处理差异
|
|
||||||
|
|
||||||
### 3. 运行迁移
|
|
||||||
|
|
||||||
在 Vercel 部署后,通过 API 端点初始化数据库:
|
|
||||||
```
|
|
||||||
POST https://your-app.vercel.app/api/init-database
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚨 常见问题
|
|
||||||
|
|
||||||
### 1. 构建失败
|
|
||||||
- 检查 `package.json` 中的 `vercel-build` 脚本
|
|
||||||
- 确保所有依赖都在 `dependencies` 中
|
|
||||||
|
|
||||||
### 2. API 路由不工作
|
|
||||||
- 检查 `vercel.json` 路由配置
|
|
||||||
- 确保后端文件路径正确
|
|
||||||
|
|
||||||
### 3. 数据库连接错误
|
|
||||||
- 验证环境变量设置
|
|
||||||
- 检查数据库连接字符串格式
|
|
||||||
|
|
||||||
### 4. CORS 错误
|
|
||||||
- 设置正确的 `CORS_ORIGIN` 环境变量
|
|
||||||
- 检查后端 CORS 配置
|
|
||||||
|
|
||||||
## 📊 性能优化
|
|
||||||
|
|
||||||
1. **启用缓存**:配置适当的缓存头
|
|
||||||
2. **压缩资源**:Vercel 自动启用 gzip
|
|
||||||
3. **CDN 加速**:静态资源自动通过 CDN 分发
|
|
||||||
4. **函数优化**:保持 API 函数轻量级
|
|
||||||
|
|
||||||
## 🔄 持续部署
|
|
||||||
|
|
||||||
Vercel 会自动监听 GitHub 仓库变化:
|
|
||||||
- 推送到 `master` 分支触发生产部署
|
|
||||||
- 推送到其他分支创建预览部署
|
|
||||||
|
|
||||||
## 📞 获取帮助
|
|
||||||
|
|
||||||
如果遇到问题:
|
|
||||||
1. 查看 Vercel 部署日志
|
|
||||||
2. 检查浏览器控制台错误
|
|
||||||
3. 参考 [Vercel 文档](https://vercel.com/docs)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
部署完成后,您的应用将在 `https://your-app-name.vercel.app` 可用!
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// Vercel API 入口文件
|
|
||||||
const app = require('../server/index.cjs');
|
|
||||||
|
|
||||||
// 导出为 Vercel 函数
|
|
||||||
module.exports = app;
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -8,7 +8,6 @@
|
|||||||
"server": "nodemon server/index.cjs",
|
"server": "nodemon server/index.cjs",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"build:prod": "tsc -b && BUILD_MODE=prod vite build",
|
"build:prod": "tsc -b && BUILD_MODE=prod vite build",
|
||||||
"vercel-build": "npm run build",
|
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"start": "node server/index.cjs",
|
"start": "node server/index.cjs",
|
||||||
|
|||||||
13
railway.json
Normal file
13
railway.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://railway.app/railway.schema.json",
|
||||||
|
"build": {
|
||||||
|
"builder": "NIXPACKS"
|
||||||
|
},
|
||||||
|
"deploy": {
|
||||||
|
"startCommand": "npm start",
|
||||||
|
"healthcheckPath": "/health",
|
||||||
|
"healthcheckTimeout": 100,
|
||||||
|
"restartPolicyType": "ON_FAILURE",
|
||||||
|
"restartPolicyMaxRetries": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,12 @@ app.use(helmet({
|
|||||||
// CORS配置
|
// CORS配置
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: process.env.NODE_ENV === 'production'
|
origin: process.env.NODE_ENV === 'production'
|
||||||
? ['http://localhost:5173', 'http://localhost:4173'] // 生产环境允许的域名
|
? [
|
||||||
|
'http://localhost:5173',
|
||||||
|
'http://localhost:4173',
|
||||||
|
/\.railway\.app$/, // Railway域名
|
||||||
|
/\.up\.railway\.app$/ // Railway新域名格式
|
||||||
|
]
|
||||||
: true, // 开发环境允许所有域名
|
: true, // 开发环境允许所有域名
|
||||||
credentials: true,
|
credentials: true,
|
||||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||||
@@ -92,36 +97,31 @@ app.use('*', (req, res) => {
|
|||||||
// 错误处理中间件
|
// 错误处理中间件
|
||||||
app.use(errorHandler);
|
app.use(errorHandler);
|
||||||
|
|
||||||
// 启动服务器(仅在非Vercel环境)
|
// 启动服务器
|
||||||
if (process.env.VERCEL !== '1') {
|
const server = app.listen(PORT, () => {
|
||||||
const server = app.listen(PORT, () => {
|
console.log(`🚀 服务器运行在 http://localhost:${PORT}`);
|
||||||
console.log(`🚀 服务器运行在 http://localhost:${PORT}`);
|
console.log(`📊 数据库文件: ${path.resolve('./numerology.db')}`);
|
||||||
console.log(`📊 数据库文件: ${path.resolve('./numerology.db')}`);
|
|
||||||
console.log(`🌍 环境: ${process.env.NODE_ENV || 'development'}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 优雅关闭
|
|
||||||
process.on('SIGTERM', () => {
|
|
||||||
console.log('收到SIGTERM信号,开始优雅关闭...');
|
|
||||||
server.close(() => {
|
|
||||||
console.log('HTTP服务器已关闭');
|
|
||||||
dbManager.close();
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
console.log('收到SIGINT信号,开始优雅关闭...');
|
|
||||||
server.close(() => {
|
|
||||||
console.log('HTTP服务器已关闭');
|
|
||||||
dbManager.close();
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log('🚀 Vercel serverless 环境已就绪');
|
|
||||||
console.log(`🌍 环境: ${process.env.NODE_ENV || 'development'}`);
|
console.log(`🌍 环境: ${process.env.NODE_ENV || 'development'}`);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
// 优雅关闭
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
console.log('收到SIGTERM信号,开始优雅关闭...');
|
||||||
|
server.close(() => {
|
||||||
|
console.log('HTTP服务器已关闭');
|
||||||
|
dbManager.close();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
console.log('收到SIGINT信号,开始优雅关闭...');
|
||||||
|
server.close(() => {
|
||||||
|
console.log('HTTP服务器已关闭');
|
||||||
|
dbManager.close();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 未捕获异常处理
|
// 未捕获异常处理
|
||||||
process.on('uncaughtException', (error) => {
|
process.on('uncaughtException', (error) => {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// 本地API客户端
|
// 本地API客户端
|
||||||
// 替代Supabase客户端,提供相同的接口
|
// 替代Supabase客户端,提供相同的接口
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ||
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3001/api';
|
||||||
(import.meta.env.PROD ? '/api' : 'http://localhost:3001/api');
|
|
||||||
|
|
||||||
interface ApiResponse<T> {
|
interface ApiResponse<T> {
|
||||||
data?: T;
|
data?: T;
|
||||||
|
|||||||
35
vercel.json
35
vercel.json
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 2,
|
|
||||||
"builds": [
|
|
||||||
{
|
|
||||||
"src": "package.json",
|
|
||||||
"use": "@vercel/static-build",
|
|
||||||
"config": {
|
|
||||||
"distDir": "dist"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "api/index.js",
|
|
||||||
"use": "@vercel/node"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"src": "/api/(.*)",
|
|
||||||
"dest": "/api/index.js"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/(.*)",
|
|
||||||
"dest": "/index.html"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"NODE_ENV": "production",
|
|
||||||
"VERCEL": "1"
|
|
||||||
},
|
|
||||||
"functions": {
|
|
||||||
"api/index.js": {
|
|
||||||
"maxDuration": 30
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user