request_preparer.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import loguru
  2. from typing import Dict, Any
  3. from core.utils.extractors import safe_extract
  4. class RequestPreparer:
  5. """
  6. 动态准备请求体:
  7. - 支持 {{var_name}} 动态占位符
  8. - 自动从上次响应根据 response_parse 配置提取对应值
  9. - 无值时使用空字符串
  10. - 可选日志记录提取失败情况
  11. """
  12. def __init__(self, response_parse_config: Dict[str, str], logger=None, aliyun_log=None):
  13. """
  14. :param response_parse_config: 如 {"next_cursor": "$.data.next_cursor"}
  15. :param logger: 可选 logger
  16. :param aliyun_log: 可选阿里云日志实例
  17. """
  18. self.response_parse_config = response_parse_config or {}
  19. self.logger = logger or loguru.logger
  20. self.aliyun_log = aliyun_log
  21. def prepare(self, request_body_config: Dict[str, Any], response_data: Dict[str, Any]) -> Dict[str, Any]:
  22. """
  23. 根据 request_body_config 和上次响应 response_data,返回可直接请求接口的 request_body
  24. """
  25. if not request_body_config:
  26. return {}
  27. prepared_body = {}
  28. for key, value in request_body_config.items():
  29. if isinstance(value, str) and "{{" in value and "}}" in value:
  30. # 提取变量名(支持后续扩展默认值)
  31. var_name = value.strip("{}").split("|")[0]
  32. # 首先尝试直接从 response_data 中获取(处理扁平字典情况)
  33. if var_name in response_data:
  34. prepared_body[key] = response_data[var_name]
  35. else:
  36. # 否则使用 JSONPath 提取(处理嵌套对象情况)
  37. jsonpath_expr = self.response_parse_config.get(var_name)
  38. if jsonpath_expr:
  39. extracted_value = safe_extract(response_data, jsonpath_expr, default="")
  40. prepared_body[key] = extracted_value
  41. # 记录提取信息(仅在有日志记录器时)
  42. if extracted_value == "" and self.logger:
  43. self.logger.debug(f"变量 {var_name} 提取结果为空,使用默认值")
  44. else:
  45. # response_parse_config 中未配置路径,默认空字符串
  46. prepared_body[key] = ""
  47. # 记录警告信息
  48. if self.logger:
  49. self.logger.warning(f"未在response_parse_config中找到变量 {var_name} 的路径配置")
  50. else:
  51. prepared_body[key] = value
  52. return prepared_body
  53. if __name__ == "__main__":
  54. # ===== 示例运行观察效果 =====
  55. request_body_config = {
  56. "cursor": "{{next_cursor}}",
  57. "category": "recommend",
  58. "flag": "{{flag}}"
  59. }
  60. response_parse_config = {
  61. "next_cursor": "$.data.next_cursor",
  62. "flag": "$.data.flag"
  63. }
  64. # 模拟响应
  65. response_data = {
  66. "data": {
  67. "next_cursor": "abc123",
  68. "flag": "on"
  69. }
  70. }
  71. preparer = RequestPreparer(response_parse_config)
  72. prepared_body = preparer.prepare(request_body_config, response_data)
  73. print("准备好的请求体:", prepared_body)
  74. # 输出: {'cursor': 'abc123', 'category': 'recommend', 'flag': 'on'}
  75. # 测试首次请求情况
  76. prepared_body_first = preparer.prepare(request_body_config, {})
  77. print("首次请求时请求体:", prepared_body_first)
  78. # 输出: {'cursor': '', 'category': 'recommend', 'flag': ''}
  79. # 测试扁平字典情况
  80. flat_data = {
  81. "next_cursor": "flat_abc123",
  82. "flag": "flat_on"
  83. }
  84. prepared_body_flat = preparer.prepare(request_body_config, flat_data)
  85. print("扁平字典请求体:", prepared_body_flat)
  86. # 输出: {'cursor': 'flat_abc123', 'category': 'recommend', 'flag': 'flat_on'}