update pay ui

This commit is contained in:
2025-12-11 21:34:20 +08:00
parent 56e980f19d
commit 54c4f64a49
3 changed files with 246 additions and 19 deletions

41
app.py
View File

@@ -1,13 +1,27 @@
# ============ Gevent Monkey Patching必须放在所有 import 之前!)============
# 用于支持 Gunicorn + gevent 异步模式,使 requests 等阻塞调用变为非阻塞
# 注意:如果使用 GeventWebSocketWorkerworker 会自动 patch这里检测避免重复
import os
if os.environ.get('GEVENT_SUPPORT', 'true').lower() == 'true':
import sys
def _is_already_patched():
"""检测是否已经被 gevent patch"""
try:
from gevent import monkey
monkey.patch_all()
print("✅ Gevent monkey patching 已启用")
return monkey.is_module_patched('socket')
except:
return False
# 只在未被 patch 且明确启用时才 patch
if os.environ.get('GEVENT_SUPPORT', 'false').lower() == 'true' and not _is_already_patched():
try:
from gevent import monkey
monkey.patch_all(thread=False, subprocess=False) # 避免 patch 某些可能有问题的模块
print("✅ Gevent monkey patching 已启用 (手动)")
except ImportError:
print("⚠️ Gevent 未安装,跳过 monkey patching")
elif _is_already_patched():
print("✅ Gevent monkey patching 已由 Worker 启用")
# ============ Gevent Monkey Patching 结束 ============
import base64
@@ -362,11 +376,30 @@ db = SQLAlchemy(app)
mail = Mail(app)
# 初始化 Flask-SocketIO用于实时事件推送
# 自动检测可用的异步模式优先级eventlet > gevent > threading
def _detect_async_mode():
"""检测可用的异步模式"""
try:
import eventlet
return 'eventlet'
except ImportError:
pass
try:
from gevent import monkey
if monkey.is_module_patched('socket'):
return 'gevent'
except ImportError:
pass
return 'gevent' # 默认使用 geventGunicorn 会 patch
_async_mode = _detect_async_mode()
print(f"📡 Flask-SocketIO async_mode: {_async_mode}")
socketio = SocketIO(
app,
cors_allowed_origins=["http://localhost:3000", "http://127.0.0.1:3000", "http://localhost:5173",
"https://valuefrontier.cn", "http://valuefrontier.cn"],
async_mode='gevent',
async_mode=_async_mode,
logger=True,
engineio_logger=False,
ping_timeout=120, # 心跳超时时间客户端120秒内无响应才断开

View File

@@ -1,16 +1,14 @@
# -*- coding: utf-8 -*-
"""
Gunicorn 配置文件 - app.py 生产环境配置(支持 Flask-SocketIO
Gunicorn 配置文件 - app.py 生产环境配置(支持 Flask-SocketIO + WebSocket
使用方式:
# 方式1: 推荐 - 使用 geventwebsocket 支持 WebSocket + 高并发
# 推荐方式: 使用此配置文件启动
gunicorn -c gunicorn_app_config.py app:app
# 方式2: 如果方式1有问题使用纯 gevent无 WebSocket
gunicorn -c gunicorn_app_config.py -k gevent app:app
# 方式3: 最简单的多进程模式(不支持 WebSocket但最稳定
gunicorn -w 4 -b 0.0.0.0:5001 --timeout 120 app:app
# 如果遇到 502 错误,可以尝试安装 eventlet 后使用:
pip install eventlet
gunicorn -k eventlet -w 1 -b 0.0.0.0:5001 --timeout 300 app:app
"""
import os
@@ -20,20 +18,19 @@ import os
# 绑定地址和端口
bind = '0.0.0.0:5001'
# Worker 进程数
# 注意geventwebsocket 要求单 worker如果用多 worker 需要用 sync 或 gevent
# Worker 进程数WebSocket 需要单 worker
workers = 1
# Worker 类型 - 使用 geventwebsocket 支持 WebSocket
# 如果遇到问题,可以命令行添加 -k gevent 覆盖此设置
# Flask-SocketIO 需要异步 worker 来支持 WebSocket
worker_class = 'geventwebsocket.gunicorn.workers.GeventWebSocketWorker'
# Worker 连接数gevent 异步模式下可以处理大量并发连接)
worker_connections = 1000
worker_connections = 2000
# 每个 worker 处理的最大请求数,超过后重启(防止内存泄漏)
max_requests = 5000
max_requests_jitter = 500
# 每个 worker 处理的最大请求数
max_requests = 0 # 禁用自动重启,避免 WebSocket 连接中断
max_requests_jitter = 0
# ==================== 超时配置 ====================
@@ -59,7 +56,8 @@ if os.path.exists(cert_file) and os.path.exists(key_file):
accesslog = '-'
errorlog = '-'
loglevel = 'info'
loglevel = 'debug' # 调试时用 debug正常运行用 info
capture_output = True # 捕获 print 输出到日志
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)sμs'
# ==================== 进程管理 ====================

196
test_wechat_api.py Normal file
View File

@@ -0,0 +1,196 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
微信 API 连接测试脚本
用于诊断微信登录 502 问题
"""
import sys
import time
def test_requests():
"""测试 requests 库是否正常工作"""
print("=" * 50)
print("🔍 测试 1: requests 库基本功能")
print("=" * 50)
try:
import requests
# 测试普通 HTTPS 请求
print(" 测试 HTTPS 请求...")
start = time.time()
response = requests.get("https://httpbin.org/get", timeout=10)
elapsed = time.time() - start
print(f" ✅ httpbin.org 请求成功: {response.status_code} ({elapsed:.2f}s)")
# 测试微信 API 连通性
print(" 测试微信 API 连通性...")
start = time.time()
response = requests.get("https://api.weixin.qq.com/", timeout=10)
elapsed = time.time() - start
print(f" ✅ 微信 API 可达: {response.status_code} ({elapsed:.2f}s)")
return True
except Exception as e:
print(f" ❌ 请求失败: {e}")
return False
def test_redis():
"""测试 Redis 连接"""
print("\n" + "=" * 50)
print("🔍 测试 2: Redis 连接")
print("=" * 50)
try:
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# 测试连接
r.ping()
print(" ✅ Redis 连接成功")
# 测试读写
r.setex("test_key", 10, "test_value")
value = r.get("test_key")
r.delete("test_key")
print(f" ✅ Redis 读写测试成功: {value}")
return True
except Exception as e:
print(f" ❌ Redis 连接失败: {e}")
return False
def test_gevent():
"""测试 gevent 环境"""
print("\n" + "=" * 50)
print("🔍 测试 3: Gevent 环境")
print("=" * 50)
try:
from gevent import monkey
is_patched = monkey.is_module_patched('socket')
print(f" Gevent monkey patched: {is_patched}")
if is_patched:
print(" ✅ Gevent 已正确 patch")
else:
print(" ⚠️ Gevent 未 patch在 Gunicorn 下应该会自动 patch")
return True
except ImportError:
print(" ⚠️ Gevent 未安装")
return False
def test_wechat_access_token():
"""测试微信 access_token 获取(模拟)"""
print("\n" + "=" * 50)
print("🔍 测试 4: 微信 API 调用(模拟)")
print("=" * 50)
try:
import requests
# 使用一个无效的 code 测试 API 是否可达
url = "https://api.weixin.qq.com/sns/oauth2/access_token"
params = {
'appid': 'test_appid',
'secret': 'test_secret',
'code': 'test_code',
'grant_type': 'authorization_code'
}
print(" 发送测试请求到微信 API...")
start = time.time()
response = requests.get(url, params=params, timeout=15)
elapsed = time.time() - start
data = response.json()
print(f" 响应时间: {elapsed:.2f}s")
print(f" 响应内容: {data}")
# 预期会返回错误(因为参数无效),但这说明 API 可达
if 'errcode' in data:
print(f" ✅ 微信 API 可达(预期的错误响应: {data.get('errmsg', '')}")
return True
else:
print(" ⚠️ 意外的响应格式")
return True
except requests.exceptions.Timeout:
print(" ❌ 请求超时 - 网络可能有问题")
return False
except requests.exceptions.SSLError as e:
print(f" ❌ SSL 错误: {e}")
print(" 可能需要更新 CA 证书或检查网络代理设置")
return False
except Exception as e:
print(f" ❌ 请求失败: {e}")
return False
def test_flask_app():
"""测试 Flask 应用是否能正常导入"""
print("\n" + "=" * 50)
print("🔍 测试 5: Flask 应用导入")
print("=" * 50)
try:
print(" 正在导入 app...")
start = time.time()
from app import app
elapsed = time.time() - start
print(f" ✅ Flask 应用导入成功 ({elapsed:.2f}s)")
return True
except Exception as e:
print(f" ❌ Flask 应用导入失败: {e}")
import traceback
traceback.print_exc()
return False
def main():
print("\n" + "=" * 60)
print(" 微信登录问题诊断工具")
print("=" * 60)
results = []
results.append(("requests 库", test_requests()))
results.append(("Redis 连接", test_redis()))
results.append(("Gevent 环境", test_gevent()))
results.append(("微信 API", test_wechat_access_token()))
# Flask 导入测试可能会比较慢,放最后
if '--skip-flask' not in sys.argv:
results.append(("Flask 应用", test_flask_app()))
print("\n" + "=" * 60)
print(" 测试结果汇总")
print("=" * 60)
all_passed = True
for name, passed in results:
status = "✅ 通过" if passed else "❌ 失败"
print(f" {name}: {status}")
if not passed:
all_passed = False
print("\n" + "=" * 60)
if all_passed:
print("✅ 所有测试通过!")
print("\n如果微信登录仍然 502请检查:")
print(" 1. Gunicorn 日志中的具体错误信息")
print(" 2. 微信开放平台的回调 URL 配置")
print(" 3. 服务器防火墙是否允许访问微信 API")
else:
print("❌ 部分测试失败,请根据上述信息排查问题")
print("=" * 60)
if __name__ == "__main__":
main()