refactor(static): 删除默认配置与本地回退逻辑,confs 改为强依赖
- 配置加载从三层(内置默认值→confs→本地config.ini回退)改为两层(confs 强依赖→环境变量覆盖) - confs 连接失败直接 sys.exit(1),不再静默使用内置默认值或回退本地 config.ini - file_config 初始值改为空字符串白名单模板,移除所有内置默认值 - 新增配置完整性校验:server.host/port、directory.root、cors.allowed_origins 必须非空 - ssl 段保留合理默认(enabled=false、cert/key 默认文件名),不强制配置 - 区分错误类型:连接拒绝/RpcError/通用异常分别打印明确错误信息到 stderr - confs 连接地址改为引导配置(环境变量 CONFS_HOST/CONFS_PORT 优先,默认 127.0.0.1:8010) - 移除 --config 命令行参数(本地 config.ini 回退已删除) - 删除 static/config.ini 本地回退文件 - 更新 _run.sh 移除 --config 参数 - 更新 static/README.md 与 confs/README.md 文档 - confs 集成关系描述更新为"confs 最先启动"
This commit is contained in:
1 parent
de0e4168b2
commit
0ae107f953
5 files changed
+121
-72
No files matched your search
+42
-16
@@ -90,26 +90,52 @@ static :9200 (Flask + CORS)
|
||||
|
||||
## 配置
|
||||
|
||||
`config.ini`:
|
||||
static 已接入 confs 统一配置服务,confs 是 static 启动的**强依赖**:
|
||||
|
||||
```ini
|
||||
[server]
|
||||
host = 127.0.0.1
|
||||
port = 9200
|
||||
1. **confs 统一配置服务** — 必须成功从 confs 拉取 `static.ini`,否则 static 启动失败直接退出(exit code 1)
|
||||
2. **环境变量覆盖**(最高优先级)— Docker/部署环境通过环境变量覆盖 confs 中的值
|
||||
|
||||
[directory]
|
||||
root = ./public
|
||||
### 配置文件
|
||||
|
||||
[ssl]
|
||||
enabled = false
|
||||
cert_file = cert.pem
|
||||
key_file = key.pem
|
||||
集中托管在 [confs/configs/static.ini](../confs/configs/static.ini),由 confs 服务分发:
|
||||
|
||||
[cors]
|
||||
# 允许跨域的 Origin 白名单(逗号分隔)
|
||||
# 注意:生产环境请勿包含 localhost / 127.0.0.1 / 通配符 *
|
||||
allowed_origins = https://qsont.me,https://yhdet.top
|
||||
```
|
||||
| Section | Key | 说明 |
|
||||
|---------|-----|------|
|
||||
| `[server]` | `host` | 监听地址 |
|
||||
| `[server]` | `port` | 监听端口 |
|
||||
| `[directory]` | `root` | 静态文件根目录(相对 BASE_DIR) |
|
||||
| `[ssl]` | `enabled` | 是否启用 TLS(`true`/`false`,默认 `false`) |
|
||||
| `[ssl]` | `cert_file` | SSL 证书路径(默认 `cert.pem`) |
|
||||
| `[ssl]` | `key_file` | SSL 私钥路径(默认 `key.pem`) |
|
||||
| `[cors]` | `allowed_origins` | CORS 白名单,逗号分隔 |
|
||||
|
||||
### 引导配置(confs 连接地址)
|
||||
|
||||
confs 自身的连接地址不通过 confs 获取(避免循环依赖),通过以下方式确定(优先级从高到低):
|
||||
- 环境变量 `CONFS_HOST` / `CONFS_PORT`
|
||||
- 默认值 `127.0.0.1:8010`
|
||||
|
||||
### 环境变量(最高优先级,覆盖 confs 配置值)
|
||||
|
||||
| 变量 | 说明 |
|
||||
|------|------|
|
||||
| `LISTEN_ADDR` | 监听地址(容器内需绑定 `0.0.0.0`) |
|
||||
| `LISTEN_PORT` | 监听端口 |
|
||||
| `STATIC_ROOT` | 静态文件根目录 |
|
||||
| `CONFS_HOST` | confs 服务主机名(引导配置,Docker 环境使用服务名) |
|
||||
| `CONFS_PORT` | confs 服务端口(引导配置) |
|
||||
|
||||
### 启动顺序要求
|
||||
|
||||
**confs 必须先于 static 启动**。若 confs 不可用:
|
||||
- static 打印致命错误到 stderr(包含 confs 地址和具体错误原因),以 exit code 1 终止
|
||||
- 不会静默使用默认值或回退本地配置文件启动
|
||||
- 配置完整性校验:若 static.ini 中缺少必需的 section/key(server.host/port、directory.root、cors.allowed_origins)且无对应环境变量覆盖,同样报错退出
|
||||
- ssl 段为可选项,未配置时默认 `enabled=false`、cert/key 使用默认文件名
|
||||
|
||||
### 历史遗留:本地 config.ini 已删除
|
||||
|
||||
旧版本的 `static/config.ini` 本地回退逻辑已移除,配置统一由 confs 服务分发。
|
||||
|
||||
## 依赖
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")" || exit
|
||||
source ./venv/bin/activate
|
||||
#exec ./fsys.bin --config config.ini 1>/dev/null
|
||||
exec python3 ./fsys.py --config config.ini 1>/dev/null
|
||||
#exec ./fsys.bin 1>/dev/null
|
||||
exec python3 ./fsys.py 1>/dev/null
|
||||
@@ -1,17 +0,0 @@
|
||||
[server]
|
||||
host = 127.0.0.1
|
||||
port = 9200
|
||||
|
||||
[directory]
|
||||
root = ./public
|
||||
|
||||
[ssl]
|
||||
enabled = false
|
||||
cert_file = cert.pem
|
||||
key_file = key.pem
|
||||
|
||||
[cors]
|
||||
# 允许跨域的 Origin 白名单(逗号分隔)
|
||||
# 注意:生产环境请勿包含 localhost / 127.0.0.1 / 通配符 *
|
||||
# 本地开发联调时可临时追加 http://localhost:9200,调试完务必移除
|
||||
allowed_origins = https://qsont.me,https://yhdet.top
|
||||
+69
-31
@@ -36,33 +36,35 @@ file_handler.setLevel(logging.INFO)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
parser = argparse.ArgumentParser(description='File Server')
|
||||
parser.add_argument('--config', type=str, default='config.ini', help='Configuration file path')
|
||||
args = parser.parse_args()
|
||||
|
||||
app = Flask(__name__)
|
||||
apply_security_headers(app)
|
||||
|
||||
# ==================== 配置文件加载 ====================
|
||||
# 加载顺序:内置默认值 → confs 统一配置服务(static.ini);
|
||||
# confs 不可用时 fail-safe 回退本地 config.ini
|
||||
CONFIG_FILE = args.config
|
||||
if not os.path.isabs(CONFIG_FILE):
|
||||
CONFIG_FILE = os.path.join(BASE_DIR, CONFIG_FILE)
|
||||
# ==================== 配置加载(两层:confs 强依赖 → 环境变量覆盖) ====================
|
||||
# confs 是 static 启动的强依赖:必须成功从 confs 拉取 static.ini,否则直接退出。
|
||||
# 环境变量优先级最高(Docker 兼容),可覆盖 confs 中的配置值。
|
||||
# confs 自身的连接地址通过引导配置确定:环境变量 CONFS_HOST/CONFS_PORT 优先,
|
||||
# 缺省使用 127.0.0.1:8010(与其他服务一致的约定)。
|
||||
|
||||
# 引导配置:confs 连接地址(不依赖 confs 本身)
|
||||
_confs_host = os.environ.get('CONFS_HOST', '127.0.0.1')
|
||||
_confs_port = int(os.environ.get('CONFS_PORT', '8010'))
|
||||
|
||||
# 白名单结构:_merge_ini 仅覆盖此处列出的 section/key,防止意外字段
|
||||
file_config = {
|
||||
'server': {'host': '0.0.0.0', 'port': '5000'},
|
||||
'directory': {'root': './public'},
|
||||
'ssl': {'enabled': 'false', 'cert_file': 'cert.pem', 'key_file': 'key.pem'},
|
||||
# CORS 白名单(逗号分隔),生产环境默认值;localhost 仅限本地开发时显式写入 config.ini
|
||||
'cors': {'allowed_origins': 'https://qsont.me,https://yhdet.top'},
|
||||
'server': {'host': '', 'port': ''},
|
||||
'directory': {'root': ''},
|
||||
'ssl': {'enabled': '', 'cert_file': '', 'key_file': ''},
|
||||
'cors': {'allowed_origins': ''},
|
||||
}
|
||||
|
||||
|
||||
def _merge_ini(text):
|
||||
"""把 ini 文本合并进 file_config(仅覆盖已知的 section/key)。"""
|
||||
ini = configparser.ConfigParser()
|
||||
ini = configparser.ConfigParser(interpolation=None)
|
||||
ini.read_string(text)
|
||||
for section in ['server', 'directory', 'ssl', 'cors']:
|
||||
for section in file_config:
|
||||
if ini.has_section(section):
|
||||
for key, value in ini[section].items():
|
||||
if key in file_config[section]:
|
||||
@@ -70,28 +72,64 @@ def _merge_ini(text):
|
||||
|
||||
|
||||
def _fetch_from_confs():
|
||||
"""从 confs 统一配置服务拉取 static.ini 全文,失败返回 None(fail-safe)。"""
|
||||
"""从 confs 统一配置服务拉取 static.ini 全文,失败直接终止进程。"""
|
||||
from pymsg import RpcClient, RpcError # noqa: E402
|
||||
try:
|
||||
from pymsg import RpcClient
|
||||
host = os.environ.get('CONFS_HOST', '127.0.0.1')
|
||||
port = int(os.environ.get('CONFS_PORT', '8010'))
|
||||
data = RpcClient(host, port, 'static', timeout=3).call(
|
||||
'get', {'name': 'static.ini'})
|
||||
client = RpcClient(_confs_host, _confs_port, 'static', timeout=5)
|
||||
data = client.call('get', {'name': 'static.ini'})
|
||||
return data.get('content')
|
||||
except Exception:
|
||||
return None
|
||||
except (ConnectionRefusedError, ConnectionError, OSError) as e:
|
||||
print(f'[static] 致命错误: 无法连接 confs 服务 ({_confs_host}:{_confs_port}): {e}',
|
||||
file=sys.stderr)
|
||||
print(f'[static] 请确认 confs 服务已启动并监听 {_confs_host}:{_confs_port}',
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except RpcError as e:
|
||||
print(f'[static] 致命错误: 从 confs 获取 static.ini 失败: {e}',
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f'[static] 致命错误: confs 配置拉取异常: {e}',
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
_confs_text = _fetch_from_confs()
|
||||
if _confs_text is not None:
|
||||
_merge_ini(_confs_text)
|
||||
logger.info("配置来源: confs 统一配置服务 (static.ini)")
|
||||
logs.info("static", "配置来源: confs 统一配置服务 (static.ini)")
|
||||
elif os.path.exists(CONFIG_FILE):
|
||||
with open(CONFIG_FILE, encoding='utf-8') as f:
|
||||
_merge_ini(f.read())
|
||||
logger.warning(f"confs 不可用,回退本地配置文件 {CONFIG_FILE}")
|
||||
logs.warning("static", f"confs 不可用,回退本地配置文件 {CONFIG_FILE}")
|
||||
_merge_ini(_confs_text)
|
||||
|
||||
# 环境变量覆盖(优先级最高,Docker 兼容)
|
||||
if os.environ.get('LISTEN_ADDR'):
|
||||
file_config['server']['host'] = os.environ['LISTEN_ADDR']
|
||||
if os.environ.get('LISTEN_PORT'):
|
||||
file_config['server']['port'] = os.environ['LISTEN_PORT']
|
||||
if os.environ.get('STATIC_ROOT'):
|
||||
file_config['directory']['root'] = os.environ['STATIC_ROOT']
|
||||
|
||||
# 配置完整性校验
|
||||
_required = {
|
||||
'server': ['host', 'port'],
|
||||
'directory': ['root'],
|
||||
'cors': ['allowed_origins'],
|
||||
}
|
||||
for section, keys in _required.items():
|
||||
for key in keys:
|
||||
if not file_config[section][key]:
|
||||
print(f'[static] 致命错误: 配置项 [{section}] {key} 缺失(static.ini 中未配置且无环境变量覆盖)',
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# ssl 段有合理默认(enabled=false,cert/key 有默认文件名),不强制要求配置
|
||||
if not file_config['ssl']['enabled']:
|
||||
file_config['ssl']['enabled'] = 'false'
|
||||
if not file_config['ssl']['cert_file']:
|
||||
file_config['ssl']['cert_file'] = 'cert.pem'
|
||||
if not file_config['ssl']['key_file']:
|
||||
file_config['ssl']['key_file'] = 'key.pem'
|
||||
|
||||
_config_source = f'confs (static.ini @ {_confs_host}:{_confs_port})'
|
||||
print(f'[static] 配置来源: {_config_source}')
|
||||
logger.info(f"配置来源: {_config_source}")
|
||||
logs.info("static", f"配置来源: {_config_source}")
|
||||
|
||||
# ==================== CORS(配置加载完成后初始化) ====================
|
||||
_cors_origins = [o.strip() for o in file_config['cors']['allowed_origins'].split(',') if o.strip()]
|
||||
|
||||
Reference in new issue
Block a user