集成生成和开发环境分别的启动方式
This commit is contained in:
184
config/README.md
Normal file
184
config/README.md
Normal 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
34
config/__init__.py
Normal 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
92
config/base.py
Normal 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
53
config/development.py
Normal 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
69
config/production.py
Normal 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
64
config/testing.py
Normal 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('测试环境启动')
|
||||
Reference in New Issue
Block a user