如何在删除浏览器历史与缓存后保留Flask会话以限制非注册用户使用次数?
解决方案
1. 基于IP地址的服务器端追踪
这种方式把用户的使用次数和过期时间存在服务器端(比如Redis或数据库),完全不依赖客户端缓存,从根源上避免用户清缓存重置次数的问题。
实现步骤:
- 安装Redis或用SQLite/MySQL做存储
- 后端获取用户真实公网IP(要考虑反向代理场景)
- 每次请求时校验该IP当日的使用次数,超过5次就拒绝
代码示例:
Flask后端(用Redis):
from flask import Flask, request, jsonify import redis from datetime import datetime, timedelta app = Flask(__name__) # 初始化Redis连接 r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True) def get_real_ip(): # 兼容反向代理(比如Nginx)的情况 if request.headers.get('X-Forwarded-For'): return request.headers.get('X-Forwarded-For').split(',')[0].strip() return request.remote_addr @app.route('/api/summarize', methods=['POST']) def handle_summarize(): user_ip = get_real_ip() today = datetime.now().strftime('%Y-%m-%d') # 构造当日使用记录的key record_key = f"daily_usage:{user_ip}:{today}" current_count = int(r.get(record_key) or 0) if current_count >= 5: return jsonify({'status': 'fail', 'msg': '今日使用次数已达上限,请明日再试'}), 403 # 这里写你的文本摘要逻辑 summary_result = "生成的摘要内容" # 增加使用次数,并设置过期时间到次日凌晨 r.incr(record_key) tomorrow = datetime.now() + timedelta(days=1) expire_at = datetime(tomorrow.year, tomorrow.month, tomorrow.day, 0, 0, 0) r.expireat(record_key, expire_at) return jsonify({'status': 'success', 'summary': summary_result, 'remaining': 5 - current_count - 1}) if __name__ == '__main__': app.run(debug=True)
前端Ajax请求:
function submitTextForSummary() { const inputText = document.getElementById('input-content').value; fetch('/api/summarize', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({'text': inputText}) }) .then(res => res.json()) .then(data => { if (data.status === 'fail') { alert(data.msg); } else { document.getElementById('summary-output').innerText = data.summary; document.getElementById('remaining-count').innerText = `今日剩余次数:${data.remaining}`; } }) .catch(err => console.error('请求出错:', err)); }
缺点:同一公网IP下的多个用户会共享次数(比如公司、家庭局域网),可能误伤正常用户。
2. 基于设备指纹的服务器端追踪
通过前端提取浏览器和设备的特征生成唯一指纹,服务器端存储这个指纹对应的使用记录。即使用户清空缓存,只要设备/浏览器的核心特征不变,就能识别出是同一个用户。
实现步骤:
- 前端组合浏览器UA、屏幕分辨率、时区等特征生成指纹
- 请求时把指纹传给后端,后端校验该指纹的当日使用次数
代码示例:
前端生成指纹:
function createDeviceFingerprint() { // 组合多个设备/浏览器特征 const deviceFeatures = [ navigator.userAgent, `${screen.width}x${screen.height}`, Intl.DateTimeFormat().resolvedOptions().timeZone, navigator.language, navigator.platform ]; // 简单转成base64作为指纹 return btoa(deviceFeatures.join('|')); } function submitTextForSummary() { const inputText = document.getElementById('input-content').value; const fingerprint = createDeviceFingerprint(); fetch('/api/summarize', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({'text': inputText, 'fingerprint': fingerprint}) }) .then(res => res.json()) .then(data => { if (data.status === 'fail') { alert(data.msg); } else { document.getElementById('summary-output').innerText = data.summary; document.getElementById('remaining-count').innerText = `今日剩余次数:${data.remaining}`; } }) .catch(err => console.error('请求出错:', err)); }
Flask后端(用Redis):
from flask import Flask, request, jsonify import redis from datetime import datetime, timedelta app = Flask(__name__) r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True) @app.route('/api/summarize', methods=['POST']) def handle_summarize(): req_data = request.get_json() fingerprint = req_data.get('fingerprint') if not fingerprint: return jsonify({'status': 'fail', 'msg': '无效请求'}), 400 today = datetime.now().strftime('%Y-%m-%d') record_key = f"daily_usage:fingerprint:{fingerprint}:{today}" current_count = int(r.get(record_key) or 0) if current_count >= 5: return jsonify({'status': 'fail', 'msg': '今日使用次数已达上限,请明日再试'}), 403 # 文本摘要逻辑 summary_result = "生成的摘要内容" r.incr(record_key) tomorrow = datetime.now() + timedelta(days=1) expire_at = datetime(tomorrow.year, tomorrow.month, tomorrow.day, 0, 0, 0) r.expireat(record_key, expire_at) return jsonify({'status': 'success', 'summary': summary_result, 'remaining': 5 - current_count - 1}) if __name__ == '__main__': app.run(debug=True)
缺点:设备指纹不是绝对唯一的,极端情况不同设备可能生成相同指纹,或者同一设备升级浏览器后指纹变化,但比单纯用IP精准得多。
3. IP+设备指纹混合方案
结合两种方式,优先用设备指纹识别用户,指纹不存在时 fallback 到IP记录,能最大程度减少误判。
核心逻辑:
- 前端同时传指纹和IP给后端
- 后端先查指纹对应的记录,没有的话再查IP的记录
- 记录时可以把指纹和IP关联起来,后续请求优先匹配指纹
额外优化建议
- 实时显示剩余次数:后端返回剩余次数字段,前端展示给用户,提升体验
- 处理动态IP:允许同一指纹关联多个IP,避免用户IP变动导致次数重置
- 防滥用:对频繁切换指纹/IP的请求,加入验证码验证
内容的提问来源于stack exchange,提问作者ficiency business
相关产品推荐
相关产品推荐

