How-to2026-09-289 мин четене

TypeScript SDK за PDF API: пет минути до първото извикване и какво остава за вас

Използвайте @pdf123/sdk от TypeScript, за да обединявате файлове, да добавяте водни знаци, да четете информация за файл и да свързвате няколко инструмента в една заявка. SDK хваща сгрешено име на инструмент или параметър преди да се качи каквото и да е; отказите на сървъра носят причина и подсказка, а повторните опити, отмяната и частичните неуспехи в партида са ваша работа.

PDF123 · Updated 2026-09-28

Когато викате PDF API от Node, комплектът за разработка @pdf123/sdk (SDK) хваща сгрешено име на инструмент или параметър, преди да се качи какъвто и да е файл. Той не прави повторни опити, не отменя вместо вас и не връща резултатите на поток. new Pdf123Client() по подразбиране сочи анонимно към https://pdf123.xyz; файловете ви се качват и се обработват там, защото няма локален двигател.

Диаграма: едно извикване минава последователно през три прага, проверката на tsc при компилация, проверката по време на изпълнение преди изпращане на заявката и отговора 400, който сървърът връща след качването; повторните опити и отмяната се оставят на извикващия, а входове над 95 MiB общо се качват автоматично на части

Два PDF файла в папка стигат за обединяване

Трябва ви Node 20.3 или по-нов, или Bun. Пакетът е ES модул: сложете кода във файл .mjs или първо изпълнете npm pkg set type=module. Сложете a.pdf и b.pdf в текущата папка.

npm install @pdf123/sdk
// merge.mjs
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const merged = await client.run("merge", {
  input: [await readFileInput("a.pdf"), await readFileInput("b.pdf")],
});
console.log(await saveResult(merged, { output: "merged.pdf" }));

След node merge.mjs терминалът отпечатва пътя на изхода, който сте подали, merged.pdf, а файлът е в текущата папка. readFileInput и saveResult са в @pdf123/sdk/node. Коренният вход зависи само от fetch и приема входовете като обикновени { name, data }, така че среда без файлова система може да ползва същия клиент. Резултатът е { data, contentType, filename, json }; data е цял Uint8Array, а Buffer.from(result.data) ви дава Buffer.

Обединяване на PDF е само един от инструментите.

Файловете се връщат в data, отчетите в json

Всеки инструмент се вика като client.run(toolName, { input, params }). Кодът по-долу продължава merge.mjs от предишния раздел, като client и saveResult вече са налични. Откъде да четете резултата, зависи от полето returns, което връща getTool и което е "file" или "json": за първото ползвайте data, за второто json.

import { getTool } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

// client comes from merge.mjs in the previous section
const marked = await client.run("watermark", {
  input: await readFileInput("a.pdf"),
  params: { watermarkText: "DRAFT", fontSize: 40 },
});
console.log(await saveResult(marked, { output: "marked.pdf" }));

const info = await client.run("get-info", { input: await readFileInput("a.pdf") });
console.log(info.json.FileSize, info.json.Encrypted);
console.log(getTool("get-info")?.returns); // "json"

Първият блок записва файла с воден знак в marked.pdf; във втория info.json е отчетът. Не е нужно да помните имена на полета, стойности по подразбиране или допустими стойности: getTool("watermark")?.fields е този каталог, а pdfx describe watermark в командния ред чете същия. TOOLS съдържа всичките 95 инструмента. Пълният справочник е в ръководството за SDK на страницата за разработчици.

За да обедините, после да добавите воден знак, после да компресирате, можете да ползвате pipeline или три последователни извиквания на run; кое от двете зависи от това дали искате междинните файлове. И тук продължаваме от client по-горе. pipeline събира трите стъпки в една заявка, междинните резултати остават на сървъра, а извикващият получава само последната стъпка, която кодът по-долу записва в out.pdf. Ако искате файла от всяка стъпка, викайте ги поотделно.

const result = await client.pipeline(
  [{ tool: "merge" }, { tool: "watermark", params: { watermarkText: "DRAFT" } }, { tool: "compress" }],
  [await readFileInput("a.pdf"), await readFileInput("b.pdf")],
);
console.log(await saveResult(result, { output: "out.pdf" }));

Конвейерът има най-много 8 стъпки. 9-ата стъпка получава HTTP 400: at most 8 pipeline steps allowed.

Анонимно, с ключ или насочено към собствения ви сървър

Ако сте задали PDFX_API_BASE, а заявките пак отиват към https://pdf123.xyz, причината е, че new Pdf123Client() не чете променливи на средата; то гледа само опциите на конструктора.

За анонимни извиквания ползвайте конструктора такъв, какъвто е. С ключ напишете new Pdf123Client({ apiKey: process.env.PDFX_API_KEY }); хедърът на заявката е X-API-KEY.

За да сочите към собствен сървър, ползвайте clientFromEnv() от @pdf123/sdk/node. Тя чете PDFX_API_BASE и PDFX_API_KEY. Можете да напишете и директно new Pdf123Client({ baseUrl: "http://localhost:8080" }). Ако адресът е недостъпен, извикването пропада; няма офлайн режим. Какво получавате и какво струва, когато файловете остават във вашата мрежа, е описано в Какво всъщност ви дава самостоятелното хостване (и какво струва).

Грешен параметър се хваща преди качването

Без това файлът първо щеше да се качи, а сгрешеното име на поле щеше да излезе чак като 400 от сървъра. Типовете на параметрите на всеки инструмент се генерират от каталога, така че три чести грешки пропадат още на етапа на tsc:

Какво пишете Грешка на компилатора (откъс)
client.run("rotat", { input }) Argument of type '"rotat"' is not assignable to parameter of type 'ToolId'
params: { watermarkTxt: "DRAFT" } Object literal may only specify known properties, but 'watermarkTxt' does not exist, завършваща с Did you mean to write 'watermarkText'?
params: { angle: 45 } (завъртането приема само 90, 180, 270) Type '45' is not assignable to type …, следвана от допустимите стойности

Правилни извиквания като { angle: 90 } или { watermarkText: "DRAFT", fontSize: 30 } се компилират. Числовите полета приемат и числа, и низове, така че fontSize: 30 и fontSize: "30" са равностойни. Проект, който не ползва TypeScript, получава същите грешки по време на изпълнение и заявката никога не се изпраща: третият случай дава Field "angle" of "rotate" must be one of: 90, 180, 270, а сгрешено име на инструмент дава unknown_tool, като подобните имена са изброени в съобщението.

Когато сървърът откаже, разклонявайте по reason

Когато сървърът отхвърли заявка, SDK хвърля Pdf123Error със status, code, reason и problem.hint. Един code може да има няколко стойности на reason, затова първо проверявайте reason, а после се връщайте към code. Три чести неуспеха, пуснати локално със същия вход, изглеждат така:

Вход status code reason hint (оригиналът е на английски)
Шифрован PDF, без подадена парола 400 bad_request password_required Provide the document password, or unlock the PDF first
Грешна парола 400 bad_request wrong_password Check the password and try again
Не е PDF или е повреден файл 400 invalid_document invalid_pdf Upload a valid, undamaged PDF; you can try repairing it first
import { Pdf123Client, Pdf123Error } from "@pdf123/sdk";
import { readFileInput } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const input = await readFileInput("locked.pdf");
try {
  await client.run("compress", { input });
} catch (error) {
  if (!(error instanceof Pdf123Error)) throw error;
  console.error(error.status, error.code, error.reason, error.problem?.hint);
  if (error.reason === "password_required") {
    await client.run("compress", { input, password: "secret" });
  }
}

Когато знаете паролата, подайте password за един файл; отключването и целевият инструмент се изпълняват в същата заявка. За повреден файл първо опитайте Поправка на PDF.

„Няма резултат“ трябва да се различава. Когато PDF към CSV не намери таблица в PDF, сървърът връща 204, а SDK хвърля code: "no_content"; причината е описана в Празен експорт на таблица (204): PDF-ът ви вероятно няма колони. Условните филтриращи инструменти смятат невярното условие за нормален изход: не хвърлят грешка и връщат matched: false с празен data.

Повторните опити, паметта и отмяната са ваша работа

Мрежовите грешки и отговорите 5xx се хвърлят такива, каквито са; SDK никога не прави повторни опити сам. За заявка, която променя състояние, подайте собствен idempotencyKey: повторното изпращане със същия ключ връща първия резултат, вместо да обработва наново, а механизмът и ограниченията са в Idempotency-Key: безопасни повторни опити за PDF задачи. Резултатите се четат в паметта цели, без поточно предаване. Когато и входът, и изходът са големи, пресметнете паметта, която заемат едновременно.

Отмяната и изтичането на времето са две различни стойности на code. Едно извикване отчита само онова, което се случи първо. Примерът по-долу ги проверява в две отделни извиквания, така че и двата клона наистина да могат да се изпълнят:

import { Pdf123Client, Pdf123Error } from "@pdf123/sdk";
import { readFileInput } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const input = await readFileInput("a.pdf");

const controller = new AbortController();
setTimeout(() => controller.abort(), 10_000);
try {
  await client.run("compress", { input, signal: controller.signal });
} catch (error) {
  if (error instanceof Pdf123Error && error.code === "cancelled") { /* вие го отменихте */ }
}

try {
  await client.run("compress", { input, timeoutMs: 60_000 });
} catch (error) {
  if (error instanceof Pdf123Error && error.code === "timeout") { /* надхвърли timeoutMs; този път без signal */ }
}

Щом сигналът за прекъсване (AbortSignal) сработи, заявката се отхвърля с code: "cancelled"; надхвърлянето на времето дава code: "timeout". Всяка заявка има време за изчакване по подразбиране 5 минути, което можете да промените при създаване на клиента или да замените за отделно извикване с timeoutMs. При качване на части всяка заявка носи това време за изчакване поотделно. Отмяната затваря само тази връзка; няма гаранция, че сървърът ще спре обработката.

Един файл пропада, останалите продължават, а обратните извиквания идват по ред на завършване

За партида входове към инструмент за един файл ползвайте runBatch. Ако един файл пропадне, останалите продължават. onResult се вика в момента, в който всеки файл приключи, така че върви по ред на завършване, а index е позицията на файла във входния масив; върнатият масив винаги е в реда на входа. Записвайте байтовете на диска вътре в това обратно извикване: retainData: false изпразва data, щом обратното извикване се върне, така че резултат, който не сте записали тук със saveResult, се губи. Ако изпълнението бъде прекъснато, вече записаните файлове остават.

Приемете, че папката съдържа три читави PDF, a.pdf, b.pdf и шифрования locked.pdf (парола secret), плюс повреден файл broken.pdf, в който има само няколко набрани знака:

import { Pdf123Client } from "@pdf123/sdk";
import { fileSource, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const results = await client.runBatch("compress", [
  fileSource("a.pdf"), fileSource("broken.pdf"), fileSource("b.pdf"), fileSource("locked.pdf"),
], {
  concurrency: 2,
  passwordFor: (file) => (file.name === "locked.pdf" ? "secret" : undefined),
  onResult: async (entry, index) => {
    console.log(index, entry.input.name, entry.ok ? "ok" : entry.error.reason);
    if (entry.ok) await saveResult(entry.result, { output: "out/" });
  },
  retainData: false,
});

По подразбиране се обработват по два файла едновременно; променя се с concurrency. fileSource(path) чете файл от диска едва когато му дойде редът, така че голяма партида от големи файлове никога не е цялата в паметта наведнъж. passwordFor позволява партида, смесваща заключени и отключени файлове, да мине наведнъж. При локално пускане на четирите файла по-горе обратното извикване получи:

1 broken.pdf invalid_pdf
0 a.pdf ok
2 b.pdf ok
3 locked.pdf ok

Редът на завършване може да е различен при всяко пускане; това е само как изглеждаше едно пускане. retainData: false прави data във върнатия масив празно; успешните файлове вече бяха записани в out/ от saveResult по-горе. Когато подадете idempotencyKey на runBatch, ключът, който реално се изпраща за всеки файл, е <key>:<index>.

Качване на части започва едва над 95 MiB общо

Тялото на директна заявка е ограничено до 100 MiB и всичко по-голямо се отхвърля; подробности има в Когато голям PDF бъде отхвърлен: лимитът от 100 MiB за тялото на заявката и грешката, която подвежда. Когато всички файлове в една заявка надхвърлят общо 95 MiB, SDK преминава към качване на части, а вашето извикване на client.run не се променя. Максимумът на сървъра по подразбиране за едно качване е 500 MiB; при самостоятелно хостване го настройте с PDFX_UPLOAD_MAX_BYTES.

За същата операция, написана с curl, MCP и командния ред, вижте Една и съща операция, четири клиента: браузър, curl, MCP, pdfx: онази публикация показва четирите извиквания една до друга, а тази разгръща само SDK. Страницата на пакета в npm е @pdf123/sdk.

Open tool
Process in the browser — no watermark, files removed after the job.
Open tool
Read next
Номерация на страниците в PDF: позиция, начален номер и клопката със завъртяните страници
Как да номерирате страниците на съществуващ PDF онлайн: изберете ъгъл, задайте начален номер като 101 и избегнете номерата настрани, които се появяват на страници, записани като завъртени.
Конвертиране на PDF в JPG или PNG: какво променя DPI и как да експортирате една страница
PDF към изображения рендира всяка страница в ZIP, като PNG, освен ако изберете JPEG. Браузърната форма има само формат и DPI; API полетата за избор на страници и за WebP се игнорират. Измерени размери на файловете при 150 и 300 DPI и как да експортирате една страница.
Снимки от телефона към PDF: защо файлът излиза огромен и страница се обръща настрани
Изображения към PDF поставя всяка снимка на отделна страница в пълния му размер в пиксели, затова три JPEG от по 3,2 MB от телефон станаха 41,5 MB PDF, а портретна снимка излезе на пейзажна страница. Смалете снимките преди конвертиране и завъртете страницата настрани след това.