十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PaddleOCR API SDK 集成测试实战:从 11 项端到端用例到 BOS 签名 URL 鉴权头 Bug 的源码级复盘

PaddleOCR API SDK 集成测试实战:从 11 项端到端用例到 BOS 签名 URL 鉴权头 Bug 的源码级复盘 PaddleOCR API SDK 集成测试实战从 11 项端到端用例到 BOS 签名 URL 鉴权头 Bug 的源码级复盘【免费下载链接】PaddleOCRTurn any PDF or image document into structured data for your AI. A powerful, lightweight OCR toolkit that bridges the gap between images/PDFs and LLMs. Supports 100 languages.项目地址: https://gitcode.com/GitHub_Trending/pa/PaddleOCR本文基于 PaddleOCR 仓库根目录下的 API SDK 集成测试报告 展开完整呈现该报告对 feature/api-sdk 分支PR #18049的 11 项端到端测试结果并重点剖析其中定位到的阻塞性 Bug——fetch_jsonl下载对象存储预签名 URL 时误带Authorization头导致 400 的问题。读完本文你可以掌握异步 Job API提交—轮询—取结果SDK 的完整调用链、预签名 URL 与 Bearer 鉴权的边界处理以及报告中所列非阻塞问题在当前仓库源码中的最新状态。一、测试背景与范围测试报告 记录了如下测试环境与被测接口项目内容测试分支feature/api-sdk (PR #18049)测试环境macOS Darwin 24.3.0, Python 3.9.6, requests 2.32.5API Endpointhttps://paddleocr.aistudio-app.com/api/v2/ocr/jobs其中 Endpoint 与 SDK 源码中的默认配置一一对应paddleocr/_api_client/_http.py 中定义了DEFAULT_BASE_URL https://paddleocr.aistudio-app.com和API_PATH /api/v2/ocr/jobs客户端在初始化时用两者拼接出 jobs 地址self._jobs_url f{self._base_url}{API_PATH}并允许通过环境变量PADDLEOCR_BASE_URL覆盖见 client.py 中的解析逻辑。被测 SDK 覆盖 Python 同步/异步两套客户端同时报告对 Go 与 TypeScript SDK 做了同构审查因此结论横跨paddleocr/_api_client/Python、api_sdk/goGo与 api_sdk/typescript/srcTypeScript三处实现。被测模型方面报告覆盖了 PP-OCRv5、PP-StructureV3、PaddleOCR-VL 与 PaddleOCR-VL-1.5 四个模型对照当前的 paddleocr/_api_client/models.py模型枚举已扩展为PP_OCRV5、PP_OCRV5_LATIN、PP_OCRV6、PP_STRUCTURE_V3、PADDLE_OCR_VL、PADDLE_OCR_VL_15、PADDLE_OCR_VL_16同步/异步客户端的 OCR 默认模型为PP_OCRV6文档解析默认模型为PADDLE_OCR_VL_16见 client.py 与 async_client.py说明报告提交后模型列表仍在迭代但验证的调用链路与鉴权机制保持不变。二、测试结果总览11 项用例全部通过报告共执行 11 项集成测试总计 11 passed, 0 failed完整继承如下#测试项结果耗时说明1OCR URL (PP-OCRv5)✅ PASS3.6sURL 输入默认参数2OCR URL 自定义 Options✅ PASS3.6s设置 use_doc_orientation_classifyTrue3Doc Parsing URL (PP-StructureV3)✅ PASS3.7s文档版面解析4Submit Poll 分步调用✅ PASS3.7s非阻塞 APIsubmit → get_result → wait_for_result5OCR 本地文件上传✅ PASS4.3sfile_path 模式6错误处理 (无效 token)✅ PASS0.2s正确抛出 AuthError7输入校验✅ PASS0.0s缺少输入 / 互斥参数均正确拦截8Context Manager (with)✅ PASS3.6swith 语句正常工作9PaddleOCR-VL 模型✅ PASS3.6sVL 模型正常返回 markdown10PaddleOCR-VL-1.5 模型✅ PASS3.6sVL-1.5 模型正常返回 markdown11Doc Parsing 文件上传 (PP-StructureV3)✅ PASS4.3s本地文件上传 文档解析这 11 项用例恰好覆盖了 SDK 的三大能力维度同步一站式调用client.ocr(file_url...)与client.parse_document(...)内部封装了提交 → 轮询 → 拉取结果全过程。从 client.py 可以看到ocr()依次调用resolve_ocr_model→_submit→self._poller.poll_until_done(job_id)→parse_ocr_result非阻塞分步调用对应报告中Submit Poll 分步调用用例即submit_ocr/submit_document_parsing先拿回Job对象再由wait_ocr_result/get_status后续处理便于并发场景下先提交、后统一等待两种输入模式file_url走 JSON bodysubmit_url构造{fileUrl, model, optionalPayload}file_path走 multipart 上传submit_file以files{file: f}提交两者互斥且缺失时会被输入校验拦截——这对应 paddleocr/_api_client/_core.py 中的validate_input_source与测试 7。值得指出的是测试 6 中无效 token 正确抛出AuthError的鉴权入口在客户端构造期即被拦截client.py 在 token 缺失时直接抛AuthError(Token is required. Set PADDLEOCR_ACCESS_TOKEN or pass token.)token 的获取顺序是显式参数 → 环境变量PADDLEOCR_ACCESS_TOKEN。三、阻塞性 Bug 剖析fetch_jsonl 误带 Authorization 头请求 BOS 预签名 URL这是整份报告最有价值的发现也是结果取不回来这一类线上问题的典型代表。3.1 现象任务提交和状态轮询均成功但在最后一步下载 JSONL 结果文件时SDK 使用带有Authorization: bearer paddle_token的 session 去请求百度 BOS 对象存储的预签名 URL。BOS 不认识这个 header返回400 Bad Request。3.2 根因HTTPClient在初始化时把 Bearer token 写入了 session 级请求头# paddleocr/_api_client/_http.py当前源码 L87-L88 self._session requests.Session() self._session.headers[Authorization] fBearer {token}而旧版fetch_jsonl()复用了该 sessionself._session.get(url)。问题在于任务完成后的结果地址是对象存储的预签名 URLURL 查询参数里已经自带鉴权信息authorizationbce-auth-v1/...。同一个请求里同时存在 Bearer 头和预签名鉴权参数两者在 BOS 侧产生冲突直接被拒绝。报告给出的最小修复是改用不携带 auth header 的独立请求# 修复前 resp self._session.get(url, timeoutself._timeout) # 修复后 resp requests.get(url, timeoutself._timeout)3.3 修复已在当前仓库落地同步 异步双路径对照当前仓库源码该修复已完整落地且两个实现风格略有差异同步路径paddleocr/_api_client/_http.py 的fetch_jsonl改为直接调用requests.get(url, timeoutself._timeout)完全脱离带鉴权的 session并附有解释性注释# Result URLs are often pre-signed object storage links.拿到文本后按行json.loads解析 JSONL解析失败抛ResultParseError。异步路径paddleocr/_api_client/_async_http.py 的fetch_jsonl则临时新建一个aiohttp.ClientSessionbare session不注入Authorization头对照 _api_headers 仅在业务 API session 中使用取回文本后同样逐行解析为 JSONL。两条路径的差异说明了一个通用原则访问业务 API与访问结果资源 URL必须使用相互隔离的鉴权上下文——前者靠 Bearer token后者靠 URL 内嵌的预签名参数。3.4 影响范围按报告的判断由于fetch_jsonl是所有结果获取路径的必经环节修复前所有实际 API 调用OCR、Doc Parsing、所有模型都无法拿到最终结果属于合入前必须修复的阻塞性 Bug。该结论与轮询器代码一致paddleocr/_api_client/_poller.py 中poll_until_done在检测到state done后唯一的结果来源就是self._http.fetch_jsonl(json_url)——它失败即意味着整条链路失败。四、SDK 调用链与轮询机制为什么单任务耗时都在 3.6s 左右报告中每个成功用例耗时集中在 3.6~4.3s这个特征值来自轮询器参数与网络往返的叠加。当前 Python 轮询器的默认参数定义在 paddleocr/_api_client/_poller.pyDEFAULT_INITIAL_INTERVAL 3.0 # 首次轮询间隔 DEFAULT_MULTIPLIER 1.5 # 指数退避倍率 DEFAULT_MAX_INTERVAL 15.0 # 间隔上限 DEFAULT_MAX_WAIT_TIME 600.0 # 总等待上限poll_until_done 的循环逻辑是先以time.monotonic()计算 deadlinestart max_wait_time→ 查询任务状态 → 若done则取jsonUrl并下载 JSONL若failed则抛JobFailedError并携带服务端errorMsg否则sleep(min(interval, remaining))后按 1.5 倍递增间隔封顶 15s继续轮询超时抛PollTimeoutError。以约 1s 的服务端处理时间加首个 3s 轮询间隔估算端到端 3.6~4.3s 的耗时与该机制自洽URL 提交与文件上传多出的约 0.6s 即文件读取/上传开销。Go SDK 保持了完全一致的退避参数api_sdk/go/poller.go 中initialInterval 3 * time.Second、multiplier 1.5、maxInterval 15 * time.Second其 pollUntilDone 用context.WithDeadline派生pollCtx超时或用户取消均能终止循环。异步 Python 版本 paddleocr/_api_client/_async_poller.py 则用asyncio事件循环的loop.time()与asyncio.sleep实现了等价的 deadline 指数退避逻辑。此外tests/api_client/ 目录下的单元测试套件test_http.py16 个用例、test_core.py6 个、test_cli.py1 个、test_resources.py3 个为这些链路提供了离线回归保障与本报告的人工集成测试形成两层验证。五、非阻塞问题清单及当前仓库中的状态复核报告还列出了 6 项合入后可迭代的非阻塞问题。以当前仓库源码逐条复核其中大部分已经修复严重度语言报告指出的问题当前源码状态中PythonAsyncAPIClient._poll_until_done使用硬编码DEFAULT_MAX_WAIT_TIME忽略用户设置的 timeout已修复async_client.py 现在将poll_timeout显式传入AsyncPoller(self._http, max_wait_timepoll_timeout)且兼容timeout参数同时覆盖request_timeout与poll_timeout中GosubmitURL/submitFile/getJobStatus未使用http.NewRequestWithContextcontext 取消无法中断请求已修复api_sdk/go/transport.go 的四个请求构造点L72、L144、L177、L209及资源下载resource.go均已改用http.NewRequestWithContext中TypeScriptpoller.ts的 sleep abort listener 未设置{ once: true }长轮询泄漏 listener已修复http.ts 与 poller.ts 中的addEventListener(abort, ...)均已带{ once: true }且finally中显式removeEventListener中TypeScripthttp.ts的fetchJsonl未检查resp.ok可能存在与 Python 相同的 BOS auth 问题已修复http.ts 的fetchJsonl以withAuth false走无鉴权请求且统一入口 fetch 对resp.ok做了检查401/403 抛AuthError、400 抛InvalidRequestError低全部轮询循环先 sleep 再 check对已完成任务多等 3 秒Python 路径已改为先查状态再 sleep_poller.py 先get_job_status后time.sleep从源码结构看 Go 的 pollUntilDone 仍是先起 timer 再查询对已完成任务可能多等一个间隔低PythonCLI argparse 的store_true传False而非None导致多余字段发送给 API从当前 cli.py 看--overwrite_resources仍采用actionstore_true其False值是否会在 payload 组装时被过滤需结合运行结果进一步确认报告中标记为低严重度这张表本身也展示了集成测试报告的价值它不只是通过/失败的清单而是把三语言 SDK 中同构的隐患鉴权头边界、context/abort 传播、listener 泄漏、轮询时序一次性横向暴露出来其中 5 项中低危问题在此后都已体现在当前源码的修复中。六、结论与工程启示报告的最终结论是修复fetch_jsonl的 auth header 问题后Python SDK 的核心功能全部正常工作——4 个模型PP-OCRv5、PP-StructureV3、PaddleOCR-VL、PaddleOCR-VL-1.5均可正常调用URL 输入和文件上传两种模式均可用错误处理和输入校验逻辑正确Go/TypeScript SDK 中的同类问题需一并排查。对集成类似异步 Job API 对象存储结果的 SDK 的开发者本报告给出三点可复用的工程经验预签名 URL 与 Bearer token 是两套互斥的鉴权体系任何复用带鉴权 session 去下载结果文件的设计都会埋下 400 的雷隔离请求上下文独立requests.get或无 header 的裸 session是正确做法端到端测试要覆盖最后一公里提交成功、轮询成功并不等于链路可用结果下载fetch_jsonl必须作为每条用例的必达终点来验证——本次正是这一环节暴露了阻塞性缺陷横向比对多语言 SDKPython 发现的鉴权边界问题在 Gocontext 传播与 TypeScriptlistener 泄漏、resp.ok检查中以不同形式存在对同构实现做 checklist 式审查能以极低成本拦截一批中危缺陷。报告与验证材料均可在仓库中继续深入总览见 TEST_REPORT.mdPython 客户端实现见 paddleocr/_api_client/client.py、paddleocr/_api_client/_http.pyGo 与 TypeScript 实现分别见 api_sdk/go/ 与 api_sdk/typescript/src/离线单元测试见 tests/api_client/。【免费下载链接】PaddleOCRTurn any PDF or image document into structured data for your AI. A powerful, lightweight OCR toolkit that bridges the gap between images/PDFs and LLMs. Supports 100 languages.项目地址: https://gitcode.com/GitHub_Trending/pa/PaddleOCR创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表