callback_server.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #!/usr/bin/env python3
  2. """
  3. 简单的回调通知监听服务器
  4. 用于测试 openapi 转账回调通知功能
  5. 使用方法:
  6. python server.py [port]
  7. 示例:
  8. python server.py 8080
  9. """
  10. import http.server
  11. import socketserver
  12. import json
  13. import logging
  14. from datetime import datetime
  15. from urllib.parse import parse_qs
  16. # 配置日志
  17. logging.basicConfig(
  18. level=logging.INFO,
  19. format='%(asctime)s - %(levelname)s - %(message)s'
  20. )
  21. logger = logging.getLogger(__name__)
  22. PORT = int(__import__('sys').argv[1]) if len(__import__('sys').argv) > 1 else 8080
  23. class CallbackHandler(http.server.BaseHTTPRequestHandler):
  24. """处理回调通知的请求处理器"""
  25. def do_POST(self):
  26. """处理 POST 请求"""
  27. try:
  28. # 获取请求内容长度
  29. content_length = int(self.headers.get('Content-Length', 0))
  30. # 读取请求体
  31. post_data = self.rfile.read(content_length)
  32. # 解析表单数据
  33. content_type = self.headers.get('Content-Type', '')
  34. logger.info("=" * 60)
  35. logger.info("收到回调通知!")
  36. logger.info("时间: %s", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
  37. logger.info("路径: %s", self.path)
  38. logger.info("Content-Type: %s", content_type)
  39. logger.info("-" * 40)
  40. # 解析并打印表单数据
  41. if 'application/x-www-form-urlencoded' in content_type:
  42. params = parse_qs(post_data.decode('utf-8'))
  43. for key, values in params.items():
  44. logger.info("%s: %s", key, values[0] if values else '')
  45. # 如果有 content 字段,尝试解析 JSON
  46. if 'content' in params:
  47. try:
  48. content_json = json.loads(params['content'][0])
  49. logger.info("-" * 40)
  50. logger.info("content 内容 (JSON):")
  51. for k, v in content_json.items():
  52. logger.info(" %s: %s", k, v)
  53. except json.JSONDecodeError:
  54. logger.warning("content 不是有效的 JSON 格式")
  55. elif 'multipart/form-data' in content_type:
  56. # 简单解析 multipart 数据
  57. logger.info("收到 multipart/form-data 类型请求")
  58. logger.info("原始数据: %s", post_data.decode('utf-8', errors='replace'))
  59. else:
  60. # 尝试作为 JSON 解析
  61. try:
  62. json_data = json.loads(post_data.decode('utf-8'))
  63. logger.info("JSON 数据:")
  64. for key, value in json_data.items():
  65. logger.info(" %s: %s", key, value)
  66. except json.JSONDecodeError:
  67. logger.info("原始数据: %s", post_data.decode('utf-8', errors='replace'))
  68. logger.info("=" * 60)
  69. # 发送成功响应
  70. self.send_response(200)
  71. self.send_header('Content-Type', 'application/json')
  72. self.send_header('Access-Control-Allow-Origin', '*')
  73. self.end_headers()
  74. response = {
  75. "code": 0,
  76. "msg": "success",
  77. "data": {
  78. "receive_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  79. "notify_id": "test_response"
  80. }
  81. }
  82. self.wfile.write(json.dumps(response).encode('utf-8'))
  83. except Exception as e:
  84. logger.error("处理请求时发生错误: %s", str(e))
  85. self.send_response(500)
  86. self.send_header('Content-Type', 'application/json')
  87. self.end_headers()
  88. error_response = {"code": -1, "msg": str(e)}
  89. self.wfile.write(json.dumps(error_response).encode('utf-8'))
  90. def do_GET(self):
  91. """处理 GET 请求 - 用于健康检查"""
  92. self.send_response(200)
  93. self.send_header('Content-Type', 'application/json')
  94. self.send_header('Access-Control-Allow-Origin', '*')
  95. self.end_headers()
  96. health_response = {
  97. "status": "ok",
  98. "service": "callback-server",
  99. "time": datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  100. }
  101. self.wfile.write(json.dumps(health_response).encode('utf-8'))
  102. def log_message(self, format, *args):
  103. """自定义日志格式"""
  104. logger.info(format % args)
  105. def main():
  106. """主函数"""
  107. print(f"""
  108. ╔═══════════════════════════════════════════════════════════╗
  109. ║ 回调通知监听服务器 ║
  110. ╠═══════════════════════════════════════════════════════════╣
  111. ║ 监听端口: {PORT:<46}║
  112. ║ 监听路径: POST /callback ║
  113. ║ 健康检查: GET / ║
  114. ╠═══════════════════════════════════════════════════════════╣
  115. ║ 按 Ctrl+C 停止服务器 ║
  116. ╚═══════════════════════════════════════════════════════════╝
  117. """)
  118. with socketserver.TCPServer(("", PORT), CallbackHandler) as httpd:
  119. logger.info("服务器启动成功,监听端口 %d", PORT)
  120. try:
  121. httpd.serve_forever()
  122. except KeyboardInterrupt:
  123. logger.info("服务器已停止")
  124. httpd.shutdown()
  125. if __name__ == "__main__":
  126. main()