接口参考

HTTP 接口

不用 WebSocket 的接入方式:POST /rpc 与 WebSocket 共用同一个端口和同一套报文,面向移动端、原生桌面与服务端。

最后更新

printlink.v1 有两条传输层,跑在同一个端口上:

传输端点适合谁
WebSocketws://127.0.0.1:17888/ws网页,有事件推送
HTTPhttp://127.0.0.1:17888/rpc移动端、原生桌面、服务端任务,无状态

两者的报文完全一样:HTTP 的请求体就是 WebSocket 的请求帧。方法集、参数、权限、 限流与错误码全部共用一套,不存在「HTTP 专用接口」。

网页请用 WebSocket

/rpc 有意不返回 CORS 头。浏览器页面跨源调用它会被浏览器拦下——这是设计取舍: 网页请用 /sdk/printlink.js 走 WebSocket,那条路径有完整的来源校验、配对与事件推送。 HTTP 传输面向的是没有 CORS 语义、也不方便维持长连接的客户端。

路由

路由说明
POST /rpc一次接口调用
PUT /rpc/assets/{uploadId}素材分片数据
GET /healthz存活探针,无需鉴权
GET /api/v1/printers/{queueId}/status打印机状态快照
GET /api/v1/printers/{queueId}/telemetry耗材 / 计数等遥测
GET /api/v1/scans/{scanId}/pages/{index}扫描成品下载

GET /rpc 返回 405。全部路由都在来源白名单之下,见安全。

报文

// 请求体
{ "type": "request", "v": 1, "id": "req_1", "method": "printer.list", "params": {} }

// 成功
{ "type": "response", "v": 1, "id": "req_1", "ok": true, "result": { "devices": [], "queues": [] } }

// 失败
{ "type": "response", "v": 1, "id": "req_1", "ok": false,
  "error": { "code": "PERMISSION_DENIED", "message": "printer.read required", "retryable": false } }
  • type 可省略(省略即视为 request)。
  • id 可省略,默认为 "",响应原样回显。
  • v 必须是 1,否则 PROTOCOL_MISMATCH。

鉴权

HTTP 没有连接,会话从每个请求的头部重建,因此令牌撤销会立即生效。

HTTP 上必须带令牌(Authorization: Bearer plk_…):来源地址不构成 HTTP 凭据——每个请求都是独立的,把地址当凭据等于让同网段任何一台机器自动获得与 「用户批准过的程序」同等的调用能力。

调用方头部结果
本机原生程序无 Origin,来自本机受信本机会话,无需令牌
远程无 Origin无 Origin,来自网络拒绝:REMOTE_NATIVE_CLIENT_DENIED
已签发令牌的应用Authorization: Bearer plk_…授权会话,权限 = 令牌权限
无令牌的应用仅 Origin只能调用握手与授权相关方法

v1.0.10 起:令牌由用户在控制台签发

auth.pair 不再返回令牌。它在 HTTP 上会以 PAIRING_REQUIRED 失败,并带上 details.remedy = "issue_token",提示你到 PrintLink 控制台「安全中心 → 令牌」 创建一把。

请把令牌作为配置项交给程序(环境变量、配置文件皆可),而不是在运行时申请:

curl -X POST http://127.0.0.1:17888/rpc \
  -H "Authorization: Bearer plk_…" \
  -H "Content-Type: application/json" \
  -d '{"v":1,"type":"request","id":"1","method":"printer.list","params":{}}'

令牌请安全保存,永远不要写进日志。

HTTP 接入总开关

控制台「安全中心 → 令牌」页有一个 HTTP 接入开关,默认开启。关闭后 HTTP 上不再承载任何受保护调用(静态路由 /sdk/printlink.js / /healthz / / 与 授权方法不受影响),WebSocket 完全不受牵连。

上传素材

WebSocket 用二进制帧携带分片信息,HTTP 把它搬到 URL 与请求头:

字段HTTP 对应
uploadId路径 /rpc/assets/{uploadId}
offset请求头 X-PrintLink-Offset(必填,必须等于已收字节数)
final请求头 X-PrintLink-Final(1 / true / yes,缺省即 true)
载荷原始请求体

分片成功的响应是传输层确认,不是完整响应封装:

{ "uploadId": "upl_…", "offset": 2726 }

完整流程:asset.begin → 一次或多次 PUT(大文件中间片带 X-PrintLink-Final: false)→ asset.commit → 得到 AssetRef。 asset.begin 命中缓存时会直接返回 asset,可以跳过分片。

状态码只是便利层

响应体永远是完整的封装,ok / error.code 才是权威。 请按 code 分支:

状态码对应错误码
200成功
400其余客户端错误(INVALID_REQUEST、DOCUMENT_INVALID、PROTOCOL_MISMATCH 等)
401TOKEN_INVALID、PAIRING_REQUIRED
403PERMISSION_DENIED(含 HTTP 接入已关闭)、ORIGIN_NOT_ALLOWED、PAIRING_DENIED、PAIRING_PENDING、REMOTE_NATIVE_CLIENT_DENIED 等
404PRINTER_NOT_FOUND、PROFILE_NOT_FOUND、JOB_NOT_FOUND、METHOD_NOT_FOUND 等
413PAYLOAD_TOO_LARGE
429RATE_LIMITED
503QUEUE_FULL
500INTERNAL

没有事件推送

HTTP 是纯请求 / 响应。任务进度用 job.get / job.list 轮询,并且要有上界; 终态只有 completed / failed / canceled。需要实时推送就回到 WebSocket—— 两条传输在同一端口上共存,同一个应用可以按需混用。

完整示例

# 1) 列打印机(令牌来自控制台「安全中心 → 令牌」,明文只显示一次)
curl -s -X POST http://127.0.0.1:17888/rpc \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer plk_…' \
  -d '{"v":1,"id":"2","method":"printer.list","params":{}}'

# 2) 上传 PDF
curl -s -X POST http://127.0.0.1:17888/rpc \
  -H 'Origin: http://com.example.printapp' -H 'Authorization: Bearer plk_…' \
  -d '{"v":1,"id":"3","method":"asset.begin",
       "params":{"mime":"application/pdf","size":2726,"sha256":"<sha256>"}}'
curl -s -X PUT http://127.0.0.1:17888/rpc/assets/<uploadId> \
  -H 'Origin: http://com.example.printapp' -H 'Authorization: Bearer plk_…' \
  -H 'X-PrintLink-Offset: 0' -H 'X-PrintLink-Final: true' \
  --data-binary @file.pdf
curl -s -X POST http://127.0.0.1:17888/rpc \
  -H 'Origin: http://com.example.printapp' -H 'Authorization: Bearer plk_…' \
  -d '{"v":1,"id":"4","method":"asset.commit","params":{"uploadId":"<uploadId>","sha256":"<sha256>"}}'

# 4) 打印,然后轮询终态
curl -s -X POST http://127.0.0.1:17888/rpc \
  -H 'Origin: http://com.example.printapp' -H 'Authorization: Bearer plk_…' \
  -d '{"v":1,"id":"5","method":"job.print","params":{"queueId":"prq_…","title":"demo",
       "source":{"items":[{"type":"pdf","asset":{"id":"asl_…","sha256":"<sha256>","mime":"application/pdf","size":2726}}]}}}'
curl -s -X POST http://127.0.0.1:17888/rpc \
  -H 'Origin: http://com.example.printapp' -H 'Authorization: Bearer plk_…' \
  -d '{"v":1,"id":"6","method":"job.get","params":{"jobId":"job_…"}}'

仓库里的 examples/http-print/print.mjs 是同一条链路的零依赖 Node 客户端:

node examples/http-print/print.mjs            # 只校验,不出纸
node examples/http-print/print.mjs --print    # 真实静默打印
node examples/http-print/print.mjs --local    # 本机原生:不带 Origin,免配对

想在浏览器里逐步看每个请求,用调试台的 HTTP 直连页 (http://127.0.0.1:17888/playground/http/)。

与 WebSocket 的差异

方面WebSocketHTTP
会话连接期内保持每请求重建(撤销立即生效)
事件推送无,靠轮询
素材分片二进制帧PUT /rpc/assets/{uploadId}
CORS不适用不发放(网页请用 WebSocket)
方法集 / 权限 / 错误码—完全相同
能力解析强制同样强制

相关页面

本页目录