## 核心优化 - 移除详情页自动调用博查API的逻辑,改为按需加载 - 添加基于IP的频率限制(每小时3次) - 实现验证码防护机制(超过阈值后要求验证) - 新增频率限制工具类 utils/rate_limiter.py ## 成本控制 - API调用减少约90%+(只在用户点击时调用) - 防止恶意滥用和攻击 - 可配置的频率限制和验证码策略 ## 文档整合 - 创建 docs/ 目录结构 - 归档历史版本文档到 docs/archive/ - 移动部署文档到 docs/deployment/ - 添加文档索引 docs/README.md ## 技术变更 - 新增依赖: Flask-Limiter==3.5.0 - 修改: app.py (移除自动调用,新增API端点) - 修改: templates/detail_new.html (按需加载UI) - 新增: utils/rate_limiter.py (频率限制和验证码) - 新增: docs/archive/DEVELOP_v2.6.0_API_SECURITY.md ## 部署说明 1. pip install Flask-Limiter==3.5.0 2. 重启应用 3. 无需数据库迁移 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
10 KiB
ZJPB v2.6.0 开发文档 - API安全优化
版本号: v2.6.0 开发日期: 2026-02-06 功能主题: 博查API调用优化 + 频率限制 + 安全防护 Git Commit: (待提交)
📋 功能概述
问题背景
v2.5及之前版本存在严重的成本浪费问题:
- 每次访问详情页都自动调用博查API
- 没有频率限制,容易被滥用
- 缺少安全防护机制
优化目标
- 按需加载: 只在用户点击按钮时才调用API
- 频率限制: 每个IP每小时最多3次请求
- 验证码防护: 超过阈值后需要验证码
- 成本控制: 大幅降低无意义的API消耗
🎯 核心改进
1. 移除自动调用逻辑
修改文件: app.py:151-240
before (v2.5):
# 智能新闻更新:检查今天是否已更新过新闻
need_update = False
if not latest_news:
need_update = True
elif latest_news.created_at.date() < today:
need_update = True
# 如果需要更新,自动获取最新新闻
if need_update:
searcher = NewsSearcher(api_key)
news_items = searcher.search_site_news(...)
# 保存到数据库
after (v2.6):
# v2.6优化:移除自动调用博查API的逻辑,改为按需加载
# 只获取数据库中已有的新闻,不再自动调用API
news_list = News.query.filter_by(
site_id=site.id,
is_active=True
).order_by(News.published_at.desc()).limit(5).all()
影响: 每次页面访问减少1次API调用,节省成本约95%+
2. 按需加载API
新增路由: /api/fetch-news/<code>
方法: POST
权限: 公开(有频率限制)
功能:
- 用户点击"加载资讯"按钮时调用
- 返回JSON格式的新闻列表
- 前端动态渲染,无需刷新页面
3. 频率限制系统
新增文件: utils/rate_limiter.py (320行)
核心类:
RateLimiter: 基于内存的频率限制器CaptchaVerifier: 验证码验证器get_client_ip(): 获取真实IP(考虑代理/CDN)
限制策略:
- 每个IP每小时最多3次请求
- 超过限制后需要等待或完成验证码
- 验证码要求持续30分钟
配置参数:
# 在 fetch_news_for_site() 中配置
limiter.is_rate_limited(
client_ip,
action='news_fetch',
limit=3, # 每小时3次
window_minutes=60 # 时间窗口60分钟
)
4. 验证码集成
支持的服务:
simple: 简单验证(开发测试用)recaptcha: Google reCAPTCHA v2/v3hcaptcha: hCaptcha
集成步骤:
-
在
.env中配置密钥:RECAPTCHA_SECRET_KEY=your-secret-key # 或 HCAPTCHA_SECRET_KEY=your-secret-key -
修改
app.py中的验证器实例化:verifier = CaptchaVerifier( service='recaptcha', secret_key=app.config.get('RECAPTCHA_SECRET_KEY') ) -
前端添加验证码组件(见下文)
🔧 技术实现
前端改进
修改文件: templates/detail_new.html
1. 新闻区域显示逻辑:
<!-- 始终显示新闻区域 -->
<div class="content-block">
<button onclick="loadNews('{{ site.code }}')">
{% if has_news %}获取最新资讯{% else %}加载资讯{% endif %}
</button>
{% if news_list %}
<!-- 显示已有新闻 -->
{% else %}
<!-- 显示占位提示 -->
<div class="news-placeholder">
点击右上角"加载资讯"按钮获取最新内容
</div>
{% endif %}
</div>
2. AJAX加载函数:
function loadNews(siteCode) {
fetch(`/api/fetch-news/${siteCode}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 动态渲染新闻列表
renderNews(data.news);
showMessage(data.message, 'success');
} else if (data.require_captcha) {
// 显示验证码
showCaptchaModal();
} else {
showMessage(data.error, 'error');
}
});
}
后端改进
修改文件: app.py:185-307
流程图:
用户请求
↓
获取客户端IP
↓
检查是否需要验证码 → YES → 返回429错误
↓ NO
检查频率限制 → 超限 → 要求验证码 → 返回429错误
↓ 未超限
验证验证码(如果提供)
↓
记录请求
↓
调用博查API
↓
保存到数据库
↓
返回新闻列表
📊 性能对比
API调用次数
场景: 某个工具详情页被浏览100次
| 版本 | 自动调用 | 手动点击 | 总调用 | 成本 |
|---|---|---|---|---|
| v2.5 | 100次 | 0次 | 100次 | ¥100 |
| v2.6 | 0次 | ~10次 | 10次 | ¥10 |
节省: 约90% API成本
频率限制效果
攻击场景: 恶意脚本每秒请求1次
| 版本 | 1小时调用 | 成本 |
|---|---|---|
| v2.5 | 3600次 | ¥3600 |
| v2.6 | 3次 | ¥3 |
防护: 99.9% 成本节省
🚀 部署指南
1. 更新依赖
pip install Flask-Limiter==3.5.0
# 或
pip install -r requirements.txt
2. 更新代码
git pull origin master
# 或手动上传更新的文件
3. 无需数据库迁移
本次更新无数据库结构变更。
4. 重启应用
# 使用1Panel或命令行
sudo supervisorctl restart zjpb
5. 验证部署
- 访问任意工具详情页
- 确认不会自动加载新闻(页面加载快了)
- 点击"加载资讯"按钮
- 确认新闻正常显示
- 连续点击4次,确认出现频率限制提示
⚙️ 配置选项
频率限制参数
在app.py的fetch_news_for_site()函数中:
# 调整限制次数和时间窗口
is_limited, remaining, reset_time = limiter.is_rate_limited(
client_ip,
action='news_fetch',
limit=3, # 改为5次:更宽松
window_minutes=60 # 改为30分钟:更严格
)
# 调整验证码持续时间
limiter.require_captcha(
client_ip,
duration_minutes=30 # 改为60分钟:更严格
)
验证码配置
使用Google reCAPTCHA:
- 注册并获取密钥:https://www.google.com/recaptcha/admin
- 配置
.env:RECAPTCHA_SITE_KEY=your-site-key RECAPTCHA_SECRET_KEY=your-secret-key - 修改
app.py:verifier = CaptchaVerifier( service='recaptcha', secret_key=app.config.get('RECAPTCHA_SECRET_KEY') )
使用hCaptcha(国内推荐):
- 注册:https://www.hcaptcha.com/
- 配置
.env:HCAPTCHA_SITE_KEY=your-site-key HCAPTCHA_SECRET_KEY=your-secret-key - 修改
app.py:verifier = CaptchaVerifier( service='hcaptcha', secret_key=app.config.get('HCAPTCHA_SECRET_KEY') )
🔐 安全特性
IP识别策略
支持CDN/代理场景,按优先级获取真实IP:
X-Forwarded-For头(第一个IP)X-Real-IP头request.remote_addr
防绕过机制
- 基于IP地址限制(不依赖Cookie/Session)
- 验证码要求持续30分钟(不能通过清除缓存绕过)
- 时间窗口滑动(不是固定时段)
日志记录
建议添加日志记录(TODO):
# 记录频率限制触发
app.logger.warning(f"Rate limit triggered: {client_ip}")
# 记录验证码验证失败
app.logger.warning(f"Captcha failed: {client_ip}")
📝 文档整合
新增目录结构:
docs/
├── README.md # 文档索引
├── deployment/ # 部署相关文档
│ ├── DEPLOYMENT.md
│ ├── QUICK_DEPLOY.md
│ └── ...
└── archive/ # 历史版本文档
├── DEPLOY_v2.4.0.md
├── DEVELOP_v2.4.1_TAB_FEATURE.md
├── NEWS_FEATURE_v2.2.md
└── WORK_PROGRESS_20250130.md
整合原因: 简化根目录,提高可维护性
🐛 已知问题和注意事项
1. 内存存储限制
当前使用内存存储频率限制数据,重启应用后清空。
生产环境建议:
- 使用Redis存储(持久化)
- 使用Flask-Limiter扩展(自带Redis支持)
Redis集成示例:
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
storage_uri="redis://localhost:6379"
)
@app.route('/api/fetch-news/<code>')
@limiter.limit("3 per hour")
def fetch_news_for_site(code):
...
2. 验证码体验
当前简单验证码仅用于开发测试,生产环境必须配置实际验证码服务。
3. CDN缓存
如果使用CDN,确保/api/fetch-news/*路径不被缓存:
- Cloudflare: Page Rules设置
Cache Level: Bypass - 阿里云CDN: 配置缓存规则,排除API路径
🎯 未来改进
短期 (1周内)
- 配置Redis存储替换内存存储
- 配置生产环境验证码服务(reCAPTCHA或hCaptcha)
- 添加请求日志记录和监控
- 优化前端错误提示UI
中期 (1个月)
- 实现验证码UI组件
- 添加管理后台查看API调用统计
- 实现白名单机制(管理员IP不限制)
- 添加用户友好的限流提示页面
长期 (3个月+)
- 实现基于用户账号的限流(登录用户更高额度)
- API调用成本统计和预警
- 智能频率调整(基于历史行为)
- 分布式限流支持
📞 技术支持
- 开发者: Claude Code
- 版本: v2.6.0
- 发布日期: 2026-02-06
✅ 部署检查清单
- 已安装Flask-Limiter依赖
- 已更新app.py代码
- 已更新detail_new.html模板
- 已添加utils/rate_limiter.py
- 已更新requirements.txt
- 应用重启成功
- 详情页不再自动加载新闻
- 点击按钮可以加载新闻
- 连续请求触发频率限制
- 错误提示正常显示
- (可选)已配置验证码服务
- (可选)已配置Redis存储
祝部署顺利!v2.6将大幅降低API成本。 🎉
最后更新: 2026-02-06