""" 请求解析工具模块 ============================================================= 提供请求数据解析相关的工具函数: - get_json_data: 从Flask请求中解析JSON数据 - require_json: 装饰器,要求请求必须包含JSON数据 - parse_request_body: 解析请求体JSON数据,返回(data, error)元组 - parse_id_list: 将逗号分隔的ID字符串解析为整数列表 - parse_batch_ids: 从请求体解析批量删除ID数组,校验并转为逗号分隔字符串 - like_escape: 转义SQL LIKE通配符,防止用户输入被当作通配符 - like_contains: 构建安全的LIKE包含查询值 """ import logging from functools import wraps logger = logging.getLogger(__name__) def get_json_data(required=True, silent=False): """ 获取请求中的JSON数据 Args: required: 是否必须获取到JSON数据,默认为True silent: 是否静默处理错误,默认为False(False时会检查Content-Type) Returns: dict: JSON数据,如果获取失败则返回None或空字典 """ from flask import request if not silent and not request.is_json: return None try: json_data = request.get_json(silent=silent) except Exception: return None if required and not json_data: return None return json_data or {} def require_json(f): """ 装饰器:要求请求必须包含JSON数据 Examples: @require_json def login(): data = get_json_data() # 业务逻辑... """ @wraps(f) def decorated_function(*args, **kwargs): from flask import request if not request.is_json: from utils import R return R.failed(msg="参数格式不正确,请使用JSON格式") json_data = request.get_json() if not json_data: from utils import R return R.failed(msg="参数不能为空") request.parsed_json = json_data return f(*args, **kwargs) return decorated_function def parse_request_body(): """ 解析请求体JSON数据 Returns: tuple: (data, error) 成功时 data 为解析后的字典,error 为 None 失败时 data 为 None,error 为错误描述字符串 """ try: data = get_json_data(required=False, silent=True) if data is None or data == {}: return None, "参数不能为空" return data, None except Exception as e: logger.error(f"解析请求体异常: {str(e)}") return None, "参数处理失败" def parse_id_list(id_str: str, separator: str = ',') -> list: """ 将逗号分隔的ID字符串解析为整数列表 Args: id_str: 逗号分隔的ID字符串,如 "1,2,3" separator: 分隔符,默认为逗号 Returns: list: 有效的整数ID列表 Example: >>> parse_id_list("1,2,3") [1, 2, 3] >>> parse_id_list("1,2,abc,3") [1, 2, 3] """ if not id_str: return [] result = [] for item in id_str.split(separator): item = item.strip() if item.isdigit(): result.append(int(item)) return result def parse_batch_ids(): """ 从请求体解析批量删除的ID数组,校验并转为逗号分隔字符串 请求体格式: [1, 2, 3] Returns: tuple: (id_str, error_response) 成功时 id_str 为 "1,2,3",error_response 为 None 失败时 id_str 为 None,error_response 为 R.failed 响应 """ from flask import request from utils import R ids = request.get_json() if not ids or not isinstance(ids, list) or len(ids) == 0: return None, R.failed("参数错误:ids必须为非空数组") try: id_list = [int(id_val) for id_val in ids] except (ValueError, TypeError): return None, R.failed("参数错误:数组元素必须为数字") return ','.join(str(id_val) for id_val in id_list), None def like_escape(value, escape_char='\\'): """ 转义SQL LIKE通配符 将用户输入中的 %、_ 和转义字符本身进行转义, 防止用户输入被当作LIKE通配符导致非预期查询结果。 Args: value: 原始输入值 escape_char: 转义字符,默认为反斜杠 Returns: str: 转义后的安全字符串 Example: >>> like_escape('100%') '100\\%' >>> like_escape('test_data') 'test\\_data' """ escaped = str(value).replace(escape_char, escape_char * 2) escaped = escaped.replace('%', escape_char + '%') escaped = escaped.replace('_', escape_char + '_') return escaped def like_contains(value, escape_char='\\'): """ 构建安全的LIKE包含查询值(前后加%) 对用户输入进行通配符转义后,前后添加 % 构建模糊查询值。 配合 SQLAlchemy 的 .like() 方法和 escape 参数使用。 Args: value: 原始输入值 escape_char: 转义字符,默认为反斜杠 Returns: str: 构建好的LIKE查询值,如 '%safe_value%' Example: >>> # SQLAlchemy 用法 >>> query = query.filter(User.name.like(like_contains(name), escape='\\')) """ return f'%{like_escape(value, escape_char)}%'