PDF 转换并发布网址接口
从理解,到动手实现。步骤、协议与可复制的示例,都在这份文档中。
接口版本:2026-10-03。PDF 先由 UniDoc 原有的 Rust pdf2htmlx 转为 contract 2 HTML,再进入现有网站发布服务。调用方无需打开编辑器或自行调用两次接口。
文件类型与路由
| 输入文件 | 调用流程 |
|---|---|
| HTML / HTM | POST /sites/publish-html,提交完整 HTML |
| MD / Markdown | POST /convert/md2unidoc,再将返回的 UDOC3 交给 /sites/publish-udoc |
UDOC,unidoc_type: "docs" | POST /sites/publish-udoc,上传原生文件 |
| PDF(新增) | POST /sites/publish-pdf,上传 PDF;服务端转换并发布 |
生产地址:https://app.unidoc.top。成功网址以接口实际返回的 url 为准,形如 https://sites.unidoc.top/p/<siteId>/;可用于 UniDoc 的 HTTPS 沙箱嵌入。
产品接口:上传 PDF
POST https://app.unidoc.top/sites/publish-pdf
Origin: https://app.unidoc.top
Content-Type: multipart/form-data; boundary=<客户端自动生成>
Cookie: <已登录 UniDoc 的产品会话;由客户端会话容器管理>| multipart 字段 | 必填 | 含义 |
|---|---|---|
pdf | 是 | PDF 原始二进制;不能传 HTML、路径字符串或 Base64 |
fileName | 是 | .pdf 文件名,不含目录,最多 160 个字符 |
requestId | 是 | 持久保存的任务 ID,1~128 UTF-8 字节,不含控制字符 |
title | 否 | 站点标题,最多 160 个字符;省略时用文件名 |
不接受 userId、sourceObjectId、inputFormat、url 等额外字段。账户归属来自认证会话;来源格式由服务端写成 pdf。重复字段、重复文件和错误文件签名会被拒绝。
浏览器使用同源会话。跨源页面不能直接借用 Cookie 调用;已有桌面产品按原发布接口的受信任会话容器接入。AI 客户端使用后文 MCP OAuth 入口。不要把 Cookie 或令牌写入接入代码、网址或日志。
// 在 app.unidoc.top 同源页面运行。
// file 是用户选择的 PDF File;taskId 必须在首次请求前保存。
async function publishPdf(file, taskId) {
const form = new FormData();
form.append('pdf', file, file.name);
form.append('fileName', file.name);
form.append('requestId', taskId);
const response = await fetch('/sites/publish-pdf', {
method: 'POST', credentials: 'same-origin', body: form
});
// 不手动设置 Content-Type,让浏览器附带正确的 boundary。
const result = await response.json();
if (!response.ok || result.status !== 'published') {
throw new Error(result.error || `发布失败:${response.status}`);
}
return result.url;
}返回值与原生来源
{
"siteId": "<服务端返回的站点 ID>",
"id": "<相同站点 ID>",
"url": "https://sites.unidoc.top/p/<siteId>/",
"status": "published",
"title": "report.pdf",
"requestId": "pdf-publish-task-001",
"replayed": false,
"contentSha256": "<公开 HTML 字节的 SHA-256>",
"source": {
"kind": "udoc", "persisted": true,
"inputFormat": "pdf", "importMode": "free-html", "editMode": "edit",
"sha256": "<UDOC 来源文件的 SHA-256>",
"exportEndpoint": "/sites/source/export", "exportMethod": "POST"
}
}返回还包含 bytes(HTML 字节数)和 createdAt。原生来源是封装了转换后 HTML 的 UDOC,保存其内联字体、图片、样式与脚本;它不是上传 PDF 的原始字节副本,也不代表已经还原为可自由重排的 Word 段落。原始 PDF 请继续保存在调用方。
来源只允许所属账户取回:POST /sites/source/export,JSON 为 {"siteId":"...","format":"udoc"};将 format 改成 html 可取回转换后的完整 HTML。公开网址不授予来源下载或编辑权限。
AI / MCP:一次调用发布 PDF
MCP 地址:https://app.unidoc.top/mcp。完成 OAuth S256 PKCE,获得 mcp:read mcp:publish 后调用 unidoc_publish_pdf。原有 HTML 工具 unidoc_publish_website 保持不变。
{
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "unidoc_publish_pdf",
"arguments": {
"pdfBase64": "<PDF 原始字节的标准 Base64,不带 data: 前缀>",
"fileName": "report.pdf",
"title": "研究报告",
"requestId": "pdf-publish-task-001"
}
}
}认证使用 Authorization: Bearer <access_token>。structuredContent 返回上面的发布结果,兼容客户端也可解析 content[0].text。必须先检查 result.isError,HTTP 200 不等于工具成功。
unidoc_get_website 和 unidoc_export_website 同样适用于 PDF 发布结果。前者查询所属账户的发布信息,后者返回转换 HTML 对应的 UDOC 来源。
限制、重试和错误
| 项目 | 规则 |
|---|---|
| 普通接口 PDF | 最大 32 MiB;multipart 总请求最大 32 MiB + 64 KiB |
| MCP PDF | 解码后最大 16 MiB;标准 Base64,最多 22,369,624 个字符;MCP 总请求最大 32 MiB |
| 转换后的 HTML | 最大 16 MiB,含内嵌字体与图片;超过限制返回 413,不静默删图或删页 |
| 转换时限 | 沿用 PDF2HTML 的 600 秒截止时间;客户端建议至少保留 720 秒请求窗口 |
| 发布执行 | 同步返回;不是提交任务即成功。收到 status: published 后才展示网址 |
| 幂等 | 相同账户、相同 requestId、相同参数和 PDF 字节返回同一网址;完成后重试不再转换 |
| 内容改变 | 同一 requestId 换文件或改标题、文件名,返回冲突;应新建任务 ID |
| 失败恢复 | 转换失败不会产生已发布页面;修复转换环境后可用原参数和同一 ID 重试 |
普通接口的典型状态:400 参数或 multipart 错误;401 未登录;403 权限或来源不允许;409 任务 ID 已用于不同内容;413 输入或转换结果超限;415 不是 multipart;422 不是 PDF 或输出资源不能独立访问;429 配额不足;502 PDF2HTML 失败;503 存储或发布忙。429 遵循 Retry-After;网络中断、超时或可重试错误不要换 ID,否则可能重复发布。
转换不能保证任意损坏、加密或复杂 PDF 都成功。结果沿用 PDF2HTML 的页面、字体与图像还原能力;扫描件不会因此自动成为 OCR 可编辑正文。失败应显示实际错误,不回退为空白网页。
接入验收
- 用包含两页、文本和背景图形的 PDF 发布,打开返回网址核对页数、文字及视觉。
- 同一任务重试得到同一网址且
replayed: true;重启后仍能重试。 - 改文件或标题但沿用旧 ID,应返回冲突;新 ID 可以发布新版。
- 取回 UDOC,核对
source.sha256,打开其中转换后的 HTML;原始 PDF 仍由调用方保存。 - 验证无登录、只读授权、跨源请求、伪造文件、超限及转换失败均不会误报发布成功。