以下是为提供的 `FunctionProcessor` 类编写的 **Markdown 格式技术文档**,适用于项目开发文档或 API 文档场景。 --- # `FunctionProcessor` 技术文档 ## 概述 `FunctionProcessor` 是一个基于 `aiohttp` 的异步请求处理器类,继承自 `BaseProcessor`。它用于将 HTTP 请求动态映射到通过 `RegisterFunction` 注册的函数上,并支持路径参数解析和运行时环境注入。该处理器特别适用于实现基于注册函数的路由分发机制。 主要功能包括: - 解析 URL 路径中的参数 - 调用已注册的同步或异步函数 - 支持运行时命名空间(`run_ns`)注入上下文变量 - 返回 `Response`、`FileResponse` 或普通内容数据 --- ## 导入依赖 ```python import inspect from appPublic.dictObject import DictObject from appPublic.registerfunction import RegisterFunction from appPublic.log import info, debug, warning, error, exception, critical from aiohttp import web from aiohttp.web_response import Response, StreamResponse from .baseProcessor import BaseProcessor ``` ### 依赖说明 | 模块 | 用途 | |------|------| | `inspect` | 判断目标函数是否为协程函数 | | `DictObject` | 将字典转换为属性可访问的对象 | | `RegisterFunction` | 获取全局注册的函数 | | `appPublic.log` | 日志输出 | | `aiohttp.web` | Web 服务核心组件 | | `BaseProcessor` | 基础处理器基类 | --- ## 类定义 ```python class FunctionProcessor(BaseProcessor): ``` 继承自 `BaseProcessor`,用于处理特定类型的 HTTP 请求并调用注册函数。 --- ## 类方法 ### `isMe(name)` ```python @classmethod def isMe(cls, name): return False ``` #### 说明 此方法用于判断当前处理器是否适用于给定名称的资源。在本实现中始终返回 `False`,表示此类不会自动匹配任何资源名 —— 其使用需显式配置。 > ⚠️ 注意:若需启用自动识别,请重写此方法以根据条件返回 `True`。 #### 参数 - `name` (`str`) - 资源名称 #### 返回值 - `bool`: 始终返回 `False` --- ## 实例方法 ### `__init__(path, resource, opts)` 构造函数,初始化处理器实例。 ```python def __init__(self, path, resource, opts): self.config_opts = opts BaseProcessor.__init__(self, path, resource) ``` #### 参数 | 参数 | 类型 | 说明 | |------|------|------| | `path` | `str` | 请求路径模板 | | `resource` | `Any` | 关联资源对象(未具体使用) | | `opts` | `dict` | 配置选项,必须包含以下键:
`leading`: 前缀路径,用于截断
`registerfunction`: 注册函数名 | #### 属性设置 - `self.config_opts`: 存储传入的配置项 - 调用父类初始化逻辑 --- ### `path_call(request, params={})` 执行注册函数的核心方法,负责解析路径、获取函数并调用。 ```python async def path_call(self, request, params={}): ``` #### 流程说明 1. 设置运行时环境(通过 `set_run_env`) 2. 提取 `params_kw` 和实际请求路径 3. 截去配置中指定的前缀(`leading`),拆分剩余路径作为位置参数 4. 从 `RegisterFunction` 中获取目标函数 5. 若函数未注册,记录错误日志并返回 `None` 6. 构造调用环境(排除敏感键) 7. 异步或同步调用函数并返回结果 #### 参数 | 参数 | 类型 | 说明 | |------|------|------| | `request` | `aiohttp.web.Request` | 当前 HTTP 请求对象 | | `params` | `dict` | 可选参数字典,可覆盖默认路径等信息 | #### 返回值 - 函数调用结果(可以是 `Response`, `str`, `dict`, 或其他类型) - 如果函数未注册,返回 `None` #### 内部逻辑细节 ##### 路径处理 ```python path1 = path[len(self.config_opts['leading']):] if path1[0] == '/': path1 = path1[1:] args = path1.split('/') ``` 例如: 若 `request.path = "/api/v1/user/123"`,且 `leading="/api/v1"`,则 `args = ['user', '123']` ##### 函数调用环境构建 ```python env = {k:v for k,v in self.run_ns.items() if k not in ['params_kw', 'request']} ``` 过滤掉 `params_kw` 和 `request`,避免重复传参冲突。 ##### 协程支持 ```python if inspect.iscoroutinefunction(f): return await f(request, params_kw, *args, **env) return f(request, params_kw, *args, **env) ``` 自动识别函数类型,确保正确调用同步或异步函数。 ##### 错误处理 ```python if f is None: error(f'{rfname=} is not registered, {rf.registKW=}') return None ``` 若函数未注册,输出调试信息并返回 `None`。 --- ### `datahandle(request)` 处理请求并生成响应内容的方法。 ```python async def datahandle(self, request): x = await self.path_call(request) if isinstance(x, web.FileResponse): self.retResponse = x elif isinstance(x, Response): self.retResponse = x else: self.content = x ``` #### 功能 调用 `path_call` 执行业务逻辑,并根据返回值类型决定如何封装响应: | 返回类型 | 处理方式 | |---------|----------| | `web.FileResponse` | 直接赋值给 `self.retResponse` | | `Response`(含子类) | 赋值给 `self.retResponse` | | 其他类型(如 `str`, `dict` 等) | 赋值给 `self.content`,由后续中间件或父类序列化 | #### 参数 - `request`: `aiohttp.web.Request` 对象 #### 影响属性 - `self.retResponse`: 成功时保存响应对象 - `self.content`: 成功时保存原始内容数据 --- ## 配置要求(`opts`) `FunctionProcessor` 必须接收如下配置项: | 键名 | 类型 | 说明 | |------|------|------| | `leading` | `str` | 需要从路径中去除的前缀,如 `/api/v1` | | `registerfunction` | `str` | 在 `RegisterFunction` 中注册的函数名称 | 示例配置: ```python opts = { "leading": "/api/v1", "registerfunction": "my_registered_handler" } ``` --- ## 使用示例 ### 注册函数示例 ```python from appPublic.registerfunction import RegisterFunction def my_handler(request, params, *args, **env): return web.json_response({"args": args, "env": env}) RegisterFunction().register("my_registered_handler", my_handler) ``` ### 创建处理器并处理请求 ```python processor = FunctionProcessor("/api/v1/data/*", None, { "leading": "/api/v1/data", "registerfunction": "my_registered_handler" }) # 在 aiohttp 路由中调用 async def handle_request(request): await processor.datahandle(request) if processor.retResponse: return processor.retResponse return web.json_response(processor.content) ``` --- ## 注意事项与限制 1. **函数注册必需**:目标函数必须提前通过 `RegisterFunction().register(name, func)` 注册。 2. **函数签名要求**:被调用函数应接受 `(request, params_kw, *args, **kwargs)` 形式的参数。 3. **路径前缀必须匹配**:`leading` 必须准确匹配请求路径开头,否则可能导致参数解析异常。 4. **非标准返回值需手动处理**:若返回非 `Response` 类型,需确保上游能正确序列化 `self.content`。 --- ## 日志输出 该类使用 `appPublic.log` 模块进行日志记录: - `error`: 函数未注册时输出详细错误信息 - (其他日志级别暂未使用) 建议开启调试日志以便追踪调用过程。 --- ## 总结 `FunctionProcessor` 提供了一种灵活的函数驱动式 Web 接口设计模式,适合微服务、插件化系统或需要动态绑定逻辑的场景。结合 `RegisterFunction` 机制,实现了低耦合、高扩展性的请求处理架构。 --- > ✅ 文档版本:1.0 > 📅 最后更新:2025-04-05