集成生成和开发环境分别的启动方式

This commit is contained in:
2025-08-17 21:25:55 +08:00
parent c869cc4911
commit 0ce2d2eab6
37 changed files with 3139 additions and 80 deletions

184
config/README.md Normal file
View File

@@ -0,0 +1,184 @@
# 配置管理说明
## 概述
本项目采用分层配置管理,支持多环境部署。配置系统基于Flask的配置机制,通过环境变量和配置文件实现灵活的配置管理。
## 配置结构
```
config/
├── __init__.py # 配置工厂和映射
├── base.py # 基础配置类
├── development.py # 开发环境配置
├── production.py # 生产环境配置
├── testing.py # 测试环境配置
└── local.py # 本地配置(git忽略)
```
## 环境变量文件
```
env.example # 环境变量示例
env.test # 测试环境变量
env.production # 生产环境变量
.env # 本地环境变量(git忽略)
```
## 使用方法
### 1. 设置环境变量
复制环境变量示例文件:
```bash
cp env.example .env
```
编辑 `.env` 文件,设置实际的环境变量值。
### 2. 在应用中使用配置
```python
from config import get_config
# 获取当前环境的配置类
config_class = get_config()
# 在Flask应用中使用
app.config.from_object(config_class)
```
### 3. 切换环境
通过设置 `FLASK_ENV` 环境变量切换环境:
```bash
# 开发环境
export FLASK_ENV=development
# 生产环境
export FLASK_ENV=production
# 测试环境
export FLASK_ENV=testing
# 本地环境
export FLASK_ENV=local
```
## 配置项说明
### 必需配置项
- `SECRET_KEY`: Flask应用密钥
- `DATABASE_URL`: 数据库连接URL
- `LLM_API_URL`: OpenAI兼容API基础URL
- `LLM_API_KEY`: OpenAI兼容API密钥
- `WX_APPID`: 微信小程序AppID
- `WX_SECRET`: 微信小程序Secret
### 可选配置项
- `FLASK_ENV`: 应用环境(默认:development)
- `CORS_ORIGINS`: 跨域域名(默认:*)
- `LOG_LEVEL`: 日志级别(默认:INFO)
- `CACHE_TYPE`: 缓存类型(默认:simple)
- `SESSION_LIFETIME_HOURS`: 会话生命周期(默认:24小时)
## 环境特定配置
### 开发环境 (development)
- 启用调试模式
- 使用SQLite数据库(如果未设置DATABASE_URL)
- 关闭CSRF保护
- 详细的日志输出
### 生产环境 (production)
- 关闭调试模式
- 启用CSRF保护
- 使用Redis缓存
- 邮件错误报告
- 严格的跨域控制
### 测试环境 (testing)
- 使用内存数据库
- 关闭CSRF保护
- 使用测试密钥
- 最短的缓存时间
### 本地环境 (local)
- 继承开发环境配置
- 可自定义本地特定设置
- 不会被提交到版本控制
## 安全注意事项
1. **敏感信息保护**
- 不要在代码中硬编码敏感信息
- 使用环境变量管理所有敏感配置
- 确保 `.env` 文件不被提交到版本控制
2. **生产环境安全**
- 使用强密码和密钥
- 设置具体的跨域域名
- 启用所有安全功能
3. **配置验证**
- 应用启动时会验证必需配置项
- 缺少必需配置项会抛出异常
## 最佳实践
1. **环境分离**
- 不同环境使用不同的配置
- 避免在代码中硬编码环境特定配置
2. **配置文档**
- 及时更新配置说明
- 记录配置项的用途和影响
3. **配置测试**
- 在测试环境中验证配置
- 确保配置变更不会影响功能
4. **配置备份**
- 备份重要的配置文件
- 记录配置变更历史
## 故障排除
### 常见问题
1. **配置加载失败**
- 检查环境变量是否正确设置
- 确认配置文件路径正确
2. **敏感信息泄露**
- 检查是否有硬编码的敏感信息
- 确认 `.env` 文件在 `.gitignore` 中
3. **环境切换失败**
- 检查 `FLASK_ENV` 环境变量
- 确认对应的配置类存在
### 调试技巧
1. **查看当前配置**
```python
from config import get_config
config = get_config()
print(config.__dict__)
```
2. **检查环境变量**
```python
import os
print(os.environ.get('FLASK_ENV'))
```
3. **验证配置项**
```python
# 在应用启动时检查配置
app.logger.info(f"当前环境: {app.config['ENV']}")
app.logger.info(f"调试模式: {app.config['DEBUG']}")
```

34
config/__init__.py Normal file
View File

@@ -0,0 +1,34 @@
import os
from .base import Config
from .development import DevelopmentConfig
from .production import ProductionConfig
from .testing import TestingConfig
from .local import LocalConfig
# 配置映射字典
config_map = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'testing': TestingConfig,
'local': LocalConfig,
'default': DevelopmentConfig
}
def get_config():
"""
根据环境变量获取对应的配置类
环境变量: FLASK_ENV
可选值: development, production, testing, local
"""
env = os.environ.get('FLASK_ENV', 'development')
return config_map.get(env, config_map['default'])
# 导出配置类
__all__ = [
'Config',
'DevelopmentConfig',
'ProductionConfig',
'TestingConfig',
'LocalConfig',
'get_config'
]

92
config/base.py Normal file
View File

@@ -0,0 +1,92 @@
import os
from datetime import timedelta
class Config:
"""
基础配置类
包含所有环境通用的配置项
"""
# Flask基础配置
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY:
raise ValueError("SECRET_KEY 环境变量未设置")
# 数据库配置
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_pre_ping': True,
'pool_recycle': 300,
}
# OpenAI兼容API配置
LLM_API_URL = os.environ.get('LLM_API_URL')
if not LLM_API_URL:
raise ValueError("LLM_API_URL 环境变量未设置")
LLM_API_KEY = os.environ.get('LLM_API_KEY')
if not LLM_API_KEY:
raise ValueError("LLM_API_KEY 环境变量未设置")
# 微信小程序配置
WX_APPID = os.environ.get('WX_APPID')
if not WX_APPID:
raise ValueError("WX_APPID 环境变量未设置")
WX_SECRET = os.environ.get('WX_SECRET')
if not WX_SECRET:
raise ValueError("WX_SECRET 环境变量未设置")
# 跨域配置
CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',')
# 日志配置
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')
LOG_FILE = os.environ.get('LOG_FILE', 'logs/app.log')
# 缓存配置
CACHE_TYPE = os.environ.get('CACHE_TYPE', 'simple')
CACHE_DEFAULT_TIMEOUT = int(os.environ.get('CACHE_DEFAULT_TIMEOUT', 300))
# 会话配置
PERMANENT_SESSION_LIFETIME = timedelta(
hours=int(os.environ.get('SESSION_LIFETIME_HOURS', 24))
)
# 文件上传配置
MAX_CONTENT_LENGTH = int(os.environ.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024)) # 16MB
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', 'uploads')
# 安全配置
WTF_CSRF_ENABLED = os.environ.get('WTF_CSRF_ENABLED', 'True').lower() == 'true'
WTF_CSRF_TIME_LIMIT = int(os.environ.get('WTF_CSRF_TIME_LIMIT', 3600))
@staticmethod
def init_app(app):
"""
初始化应用配置
"""
# 创建必要的目录
os.makedirs('logs', exist_ok=True)
os.makedirs('uploads', exist_ok=True)
# 配置日志
import logging
from logging.handlers import RotatingFileHandler
if not app.debug and not app.testing:
file_handler = RotatingFileHandler(
Config.LOG_FILE,
maxBytes=10240000,
backupCount=10
)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('应用启动')

53
config/development.py Normal file
View File

@@ -0,0 +1,53 @@
from .base import Config
class DevelopmentConfig(Config):
"""
开发环境配置
"""
DEBUG = True
TESTING = False
# 开发环境数据库配置(如果未设置环境变量,使用SQLite)
def __init__(self):
super().__init__()
if not self.SQLALCHEMY_DATABASE_URI:
self.SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
# 开发环境日志配置
LOG_LEVEL = 'DEBUG'
LOG_FILE = 'logs/dev.log'
# 开发环境缓存配置
CACHE_TYPE = 'simple'
CACHE_DEFAULT_TIMEOUT = 60 # 开发环境缓存时间较短
# 开发环境安全配置
WTF_CSRF_ENABLED = False # 开发环境关闭CSRF保护
# 开发环境会话配置
SESSION_LIFETIME_HOURS = 24
# 开发环境文件上传配置
MAX_CONTENT_LENGTH = 32 * 1024 * 1024 # 32MB
UPLOAD_FOLDER = 'uploads/dev'
# 开发环境跨域配置
CORS_ORIGINS = ['http://localhost:3000', 'http://127.0.0.1:3000', '*']
@staticmethod
def init_app(app):
Config.init_app(app)
# 开发环境特定初始化
import logging
app.logger.setLevel(logging.DEBUG)
# 开发环境控制台输出
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s'
))
app.logger.addHandler(console_handler)
app.logger.info('开发环境启动')

69
config/production.py Normal file
View File

@@ -0,0 +1,69 @@
import os
from .base import Config
class ProductionConfig(Config):
"""
生产环境配置
"""
DEBUG = False
TESTING = False
# 生产环境日志配置
LOG_LEVEL = 'WARNING'
LOG_FILE = 'logs/production.log'
# 生产环境缓存配置
CACHE_TYPE = 'redis'
CACHE_REDIS_URL = os.environ.get('REDIS_URL')
CACHE_DEFAULT_TIMEOUT = 3600 # 1小时
# 生产环境安全配置
WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = 3600
# 生产环境会话配置
SESSION_LIFETIME_HOURS = 168 # 7天
# 生产环境文件上传配置
MAX_CONTENT_LENGTH = 8 * 1024 * 1024 # 8MB
UPLOAD_FOLDER = 'uploads/production'
# 生产环境跨域配置(需要设置具体的域名)
CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '').split(',')
if not CORS_ORIGINS or CORS_ORIGINS == ['']:
# 如果没有设置,使用默认值而不是抛出异常
CORS_ORIGINS = ['https://yourdomain.com']
# 生产环境性能配置
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_pre_ping': True,
'pool_recycle': 300,
'pool_size': 20,
'max_overflow': 30,
}
@staticmethod
def init_app(app):
Config.init_app(app)
# 生产环境特定初始化
import logging
app.logger.setLevel(logging.WARNING)
# 生产环境错误处理
if not app.debug and not app.testing:
import logging
from logging.handlers import SMTPHandler
# 邮件错误报告(如果配置了邮件服务器)
mail_handler = SMTPHandler(
mailhost=(os.environ.get('MAIL_SERVER', 'localhost'),
int(os.environ.get('MAIL_PORT', 25))),
fromaddr=os.environ.get('MAIL_FROM', 'noreply@example.com'),
toaddrs=os.environ.get('ADMIN_EMAIL', '').split(','),
subject='应用错误报告'
)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
app.logger.info('生产环境启动')

64
config/testing.py Normal file
View File

@@ -0,0 +1,64 @@
import os
import tempfile
from .base import Config
class TestingConfig(Config):
"""
测试环境配置
"""
DEBUG = False
TESTING = True
# 测试环境数据库配置(使用内存数据库)
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
# 测试环境日志配置
LOG_LEVEL = 'DEBUG'
LOG_FILE = 'logs/test.log'
# 测试环境缓存配置
CACHE_TYPE = 'simple'
CACHE_DEFAULT_TIMEOUT = 10 # 测试环境缓存时间很短
# 测试环境安全配置
WTF_CSRF_ENABLED = False # 测试环境关闭CSRF保护
WTF_CSRF_TIME_LIMIT = 300
# 测试环境会话配置
SESSION_LIFETIME_HOURS = 1
# 测试环境文件上传配置
MAX_CONTENT_LENGTH = 1 * 1024 * 1024 # 1MB
UPLOAD_FOLDER = tempfile.mkdtemp()
# 测试环境跨域配置
CORS_ORIGINS = ['*']
# 测试环境API配置(使用测试密钥)
LLM_API_KEY = 'test-api-key'
WX_APPID = 'test-wx-appid'
WX_SECRET = 'test-wx-secret'
# 测试环境性能配置
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_pre_ping': False, # 测试环境关闭连接池检查
'pool_recycle': -1,
}
@staticmethod
def init_app(app):
Config.init_app(app)
# 测试环境特定初始化
import logging
app.logger.setLevel(logging.DEBUG)
# 测试环境控制台输出
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s'
))
app.logger.addHandler(console_handler)
app.logger.info('测试环境启动')