BitMiracle Docotic PDF與IronPDF:技術比較指南
當.NET開發者評估PDF生成解決方案時,Gotenberg作為一個基於Docker的微服務,通過REST API調用將HTML轉換為PDF脫穎而出。 雖然能適應不同的架構,Gotenberg引入了顯著的基礎設施開銷——Docker容器、網路延遲和操作複雜性。 IronPDF提供了一個替代方案:一個內部處理的NuGet包,提供相同的基於Chromium的渲染,而不需要容器、網路調用或基礎設施管理。
此比較從技術相關的維度來看兩種解決方案,以幫助專業開發者和建築師為其.NET PDF需求做出明智的決策。
了解Gotenberg
Gotenberg是一個基於Docker的PDF生成微服務架構。 它作為一個獨立容器運行,公開REST API端點用於將HTML、URL和其他格式轉換為PDF。 每個PDF操作都需要發送HTTP調用到Gotenberg服務。
Gotenberg使用POST /forms/chromium/convert/url作為URL到PDF的端點。 配置通過multipart/form-data傳遞,使用以字串為基礎的參數,如marginBottom(以英寸計)。 該服務需要Docker部署、容器編排(Kubernetes/Docker Compose)和網路基礎設施。
該架構需要:
- Docker容器部署和管理
- 每個PDF請求的網路通信(容器HTTP往返)
- 容器冷啟動處理(首次請求的初始化延遲)
- 健康檢查端點和服務監控
- 每次請求的multipart/form-data構建
了解IronPDF
IronPDF是一個原生的.NET程式庫,作為NuGet包在內部處理運行。 它提供基於Chromium的HTML渲染,無需外部服務、網路調用或容器基礎設施。
IronPDF使用RenderUrlAsPdf()。 配置上使用的C#型別屬性為MarginBottom(以毫米計)。 文件使用BinaryData存取。
該程式庫僅需要:
- NuGet包安裝(
dotnet add package IronPdf) - 授權金鑰配置
- 標準.NET專案設置
架構與基礎設施比較
這些解決方案之間的基本區別在於其部署和運行時架構。
| 因素 | Gotenberg | IronPDF |
|---|---|---|
| 部署 | Docker容器+編排 | 單一NuGet套件 |
| 架構 | 微服務(REST API) | 內部程式庫 |
| 每次請求的延遲 | 容器HTTP往返 | 內部處理(最小開銷) |
| 冷啟動 | 容器初始化延遲 | 引擎初始化(僅首次渲染) |
| 基礎設施 | Docker,Kubernetes,負載平衡器 | 不需要 |
| 網路依賴 | 需要 | None |
| 故障模式 | 網路,容器,服務故障 | 標準.NET例外 |
| API風格 | REST multipart/form-data | 原生C#方法調用 |
| 擴展性 | 水平擴展(更多容器) | 垂直擴展(內部處理) |
| 除錯 | 分佈式跟踪 | 標準除錯器 |
| 記憶體管理 | 獨立容器分配 | 共享應用程式記憶體 |
| 版本控制 | 容器映像標籤 | NuGet包版本 |
| 健康檢查 | 需要HTTP端點 | 不需要(內部處理) |
| CI/CD複雜性 | 容器構建、註冊表推送 | 標準.NET構建 |
Gotenberg的基於Docker方法需要容器部署、健康監控和網路基礎設施管理。 IronPDF通過運行在內部處理中完全消除了這個基礎設施層。
程式碼比較:常見的 PDF 操作
基本的HTML到PDF轉換
最基本的操作明顯展示了架構的差異。
Gotenberg:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergExample
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Hello from Gotenberg</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("output.pdf", pdfBytes);
Console.WriteLine("PDF generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergExample
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Hello from Gotenberg</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("output.pdf", pdfBytes);
Console.WriteLine("PDF generated successfully");
}
}Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Module GotenbergExample
Async Function Main() As Task
Dim gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html"
Using client As New HttpClient()
Using content As New MultipartFormDataContent()
Dim html = "<html><body><h1>Hello from Gotenberg</h1></body></html>"
content.Add(New StringContent(html), "files", "index.html")
Dim response = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes = Await response.Content.ReadAsByteArrayAsync()
Await File.WriteAllBytesAsync("output.pdf", pdfBytes)
Console.WriteLine("PDF generated successfully")
End Using
End Using
End Function
End ModuleIronPDF:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfExample
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var html = "<html><body><h1>Hello from IronPDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfExample
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var html = "<html><body><h1>Hello from IronPDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully");
}
}Imports System
Imports IronPdf
Class IronPdfExample
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html = "<html><body><h1>Hello from IronPDF</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF generated successfully")
End Sub
End Class該服務需要建立index.html)作為文件附件新增HTML,對端點進行異步HTTP POST,讀取響應字節並寫入磁盤。 每次請求都經過網路,帶有相關的延遲和故障模式。
IronPDF建立SaveAs()保存。 該操作是同步的、內部處理的,使用型別化方法而不是基於字串的表單資料。
想了解進階HTML渲染選項,請參閱HTML到PDF轉換指南。
URL 到 PDF 轉換
將在線網頁轉換為PDF顯示了類似的架構模式。
Gotenberg:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergUrlToPdf
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/url";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("https://example.com"), "url");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("webpage.pdf", pdfBytes);
Console.WriteLine("PDF from URL generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergUrlToPdf
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/url";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("https://example.com"), "url");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("webpage.pdf", pdfBytes);
Console.WriteLine("PDF from URL generated successfully");
}
}Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Module GotenbergUrlToPdf
Async Function Main() As Task
Dim gotenbergUrl As String = "http://localhost:3000/forms/chromium/convert/url"
Using client As New HttpClient()
Using content As New MultipartFormDataContent()
content.Add(New StringContent("https://example.com"), "url")
Dim response As HttpResponseMessage = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes As Byte() = Await response.Content.ReadAsByteArrayAsync()
Await File.WriteAllBytesAsync("webpage.pdf", pdfBytes)
Console.WriteLine("PDF from URL generated successfully")
End Using
End Using
End Function
End ModuleIronPDF:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfUrlToPdf
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF from URL generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfUrlToPdf
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF from URL generated successfully");
}
}Imports System
Imports IronPdf
Class IronPdfUrlToPdf
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("PDF from URL generated successfully")
End Sub
End Class容器使用/forms/chromium/convert/url端點,URL以表單資料的形式傳遞。 IronPDF直接調用RenderUrlAsPdf()與URL字串——單次方法調用取代了HTTP基礎設施。
自定義頁面尺寸和邊距
配置處理揭示了API設計的差異。
Gotenberg:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergCustomSize
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
content.Add(new StringContent("8.5"), "paperWidth");
content.Add(new StringContent("11"), "paperHeight");
content.Add(new StringContent("0.5"), "marginTop");
content.Add(new StringContent("0.5"), "marginBottom");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes);
Console.WriteLine("Custom size PDF generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergCustomSize
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
content.Add(new StringContent("8.5"), "paperWidth");
content.Add(new StringContent("11"), "paperHeight");
content.Add(new StringContent("0.5"), "marginTop");
content.Add(new StringContent("0.5"), "marginBottom");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes);
Console.WriteLine("Custom size PDF generated successfully");
}
}Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Class GotenbergCustomSize
Shared Async Function Main() As Task
Dim gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html"
Using client As New HttpClient()
Using content As New MultipartFormDataContent()
Dim html = "<html><body><h1>Custom Size PDF</h1></body></html>"
content.Add(New StringContent(html), "files", "index.html")
content.Add(New StringContent("8.5"), "paperWidth")
content.Add(New StringContent("11"), "paperHeight")
content.Add(New StringContent("0.5"), "marginTop")
content.Add(New StringContent("0.5"), "marginBottom")
Dim response = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes = Await response.Content.ReadAsByteArrayAsync()
Await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes)
Console.WriteLine("Custom size PDF generated successfully")
End Using
End Using
End Function
End ClassIronPDF:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;
class IronPdfCustomSize
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 50;
renderer.RenderingOptions.MarginBottom = 50;
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-size.pdf");
Console.WriteLine("Custom size PDF generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;
class IronPdfCustomSize
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 50;
renderer.RenderingOptions.MarginBottom = 50;
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-size.pdf");
Console.WriteLine("Custom size PDF generated successfully");
}
}Imports System
Imports IronPdf
Imports IronPdf.Rendering
Module IronPdfCustomSize
Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
renderer.RenderingOptions.MarginTop = 50
renderer.RenderingOptions.MarginBottom = 50
Dim html As String = "<html><body><h1>Custom Size PDF</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom-size.pdf")
Console.WriteLine("Custom size PDF generated successfully")
End Sub
End Module此方法使用基於字串的參數("0.5")新增到multipart form資料中。 紙張尺寸以英寸計算。 每個參數都是一個獨立的Add()調用,沒有型別檢查或IntelliSense支持。
IronPDF使用RenderingOptions上的型別屬性。 PdfPaperSize.Letter),且邊距以毫米為單位。 型別化API提供編譯時檢查和IDE支持。
在IronPDF教程中了解有關渲染配置的更多資訊。
API映射參考
對於評估Gotenberg遷移或比較功能的開發者,這個映射顯示了等效操作:
端點到方法的映射
| Gotenberg路由 | IronPDF等效 |
|---|---|
POST /forms/chromium/convert/html | ChromePdfRenderer.RenderHtmlAsPdf() |
POST /forms/chromium/convert/url | ChromePdfRenderer.RenderUrlAsPdf() |
POST /forms/chromium/convert/markdown | 首先將Markdown渲染為HTML |
POST /forms/pdfengines/merge | PdfDocument.Merge() |
POST /forms/pdfengines/metadata/read | pdf.MetaData |
POST /forms/pdfengines/metadata/write | pdf.MetaData.Author = "..." |
GET /health | 不適用 |
表單參數到RenderingOptions的映射
| Gotenberg參數 | IronPDF屬性 | 轉換說明 |
|---|---|---|
paperWidth(英寸) | RenderingOptions.SetCustomPaperSizeInInches() | 使用方法進行自定義 |
paperHeight(英寸) | RenderingOptions.SetCustomPaperSizeInInches() | 使用方法進行自定義 |
marginTop(英寸) | RenderingOptions.MarginTop | 乘以25.4以便轉換為毫米 |
marginBottom(英寸) | RenderingOptions.MarginBottom | 乘以25.4以便轉換為毫米 |
marginLeft(英寸) | RenderingOptions.MarginLeft | 乘以25.4以便轉換為毫米 |
marginRight(英寸) | RenderingOptions.MarginRight | 乘以25.4以便轉換為毫米 |
printBackground | RenderingOptions.PrintHtmlBackgrounds | 布林值 |
landscape | RenderingOptions.PaperOrientation | Landscape枚舉 |
scale | RenderingOptions.Zoom | 百分比(100=1.0) |
waitDelay | RenderingOptions.RenderDelay | 轉換為毫秒 |
emulatedMediaType | RenderingOptions.CssMediaType | Print |
注意單位轉換:Gotenberg使用英寸為邊距(例如,"0.5"=0.5英寸=12.7毫米),而IronPDF使用毫米。
基礎設施比較
Gotenberg Docker Compose
Gotenberg需要容器基礎設施:
# Gotenberg requires container management
version: '3.8'
services:
app:
depends_on:
- gotenberg
environment:
- GOTENBERG_URL=http://gotenberg:3000
gotenberg:
image: gotenberg/gotenberg:8
ports:
- "3000:3000"
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s# Gotenberg requires container management
version: '3.8'
services:
app:
depends_on:
- gotenberg
environment:
- GOTENBERG_URL=http://gotenberg:3000
gotenberg:
image: gotenberg/gotenberg:8
ports:
- "3000:3000"
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30sIronPDF配置
IronPDF不需要額外的服務:
# IronPDF - No additional services needed
version: '3.8'
services:
app:
environment:
- IRONPDF_LICENSE_KEY=${IRONPDF_LICENSE_KEY}
# No Gotenberg service. No health checks. No resource limits.# IronPDF - No additional services needed
version: '3.8'
services:
app:
environment:
- IRONPDF_LICENSE_KEY=${IRONPDF_LICENSE_KEY}
# No Gotenberg service. No health checks. No resource limits.基礎設施差異是巨大的:Gotenberg需要容器部署、健康監控、資源分配和服務依賴。 IronPDF隨應用程式內部運行。
性能特徵
| 因素 | Gotenberg | IronPDF |
|---|---|---|
| 處理 | 每次請求的容器HTTP往返 | 內部處理(無網路開銷) |
| 啟動 | 每次部署/擴展事件的容器初始化 | 每個應用程式生命周期僅需一次引擎初始化 |
| 記憶體 | 獨立容器分配 | 共享應用程式記憶體 |
| 後續渲染 | 每次請求持續的網路開銷 | 初始化後的最小開銷 |
Gotenberg的架構為每個請求增加了網路往返開銷,且容器冷啟動在每次部署或擴展事件中發生。 IronPDF的首次渲染會引起引擎初始化,但後續渲染在內部處理中運行,開銷最小。
當團隊考慮從Gotenberg轉向IronPDF時
開發團隊評估從Gotenberg轉向IronPDF有幾個原因:
基礎設施開銷:該服務需要Docker、容器編排(Kubernetes/Docker Compose)、服務發現和負載平衡。 尋求簡化部署的團隊會發現IronPDF的僅需NuGet方法消除了這些基礎設施問題。
網路延遲: 每一次通過容器的PDF操作都需要對單獨的服務進行HTTP調用,這對於每個請求都增加了網路往返開銷。對於高並發的應用程式,這些開銷會累積。 IronPDF的內部處理方法在初始化後幾乎沒有開銷。
冷啟動問題: 容器啟動給首次請求增加了初始化延遲。 即便是暖容器也有網路開銷。 每次傳遞啟動、擴展事件或部署都會觸發冷啟動。 IronPDF的初始化在每應用程式生命週期中僅發生一次。
操作複雜性: 需要將容器健康、擴展、日誌和監控作為獨立問題進行管理。 網路超時、服務無法存取和容器崩潰成為應用程式問題。 IronPDF使用標準.NET異常處理。
Multipart Form資料API: 每次服務請求都需要構建帶有基於字串參數的multipart/form-data資料負載——冗長且沒有編譯時型別檢查。 IronPDF提供了帶有IntelliSense支持的型別化C#屬性。
版本管理: 它的容器鏡像獨立於您的應用程式更新。 API變更可能會破壞整合。 通過NuGet管理IronPDF版本,使用標準的.NET依賴管理。
優勢和考量
Gotenberg優勢
- 多語言架構: 可與任何能夠發起HTTP調用的語言一起使用
- 語言無關: 不依賴於.NET生態系統
- MIT授權: 免費且開源
- 微服務模式: 適合容器化架構
Gotenberg考量
- 基礎設施開銷: 需要Docker、Kubernetes、負載平衡器
- 網路延遲: 每次請求的容器HTTP往返
- 冷啟動: 容器初始化延遲
- 基於字串的API: 沒有型別安全或IntelliSense
- 分佈式除錯: 需要分佈式跟踪
- 健康監控: 需要額外的端點來管理
IronPDF的優勢
IronPDF考量
- .NET特定: 為.NET生態系統設計
- 商業許可:生產使用需要商業許可
Gotenberg和IronPDF代表了在.NET應用中生成PDF的根本不同的兩種方法。 Gotenberg的基於Docker的微服務架構引入了容器管理、網路延遲和運行複雜性。 每次PDF操作都需要HTTP通信,帶有相關的失敗模式和冷啟動懲罰。
IronPDF提供了與內部處理程式庫相同的基於Chromium的渲染。 NuGet包消除了Docker容器、網路調用和基礎設施管理。 型別化的C# API取代了基於字串的multipart form資料。 標準.NET異常處理取代了HTTP狀態碼和網路故障模式。
隨著組織計劃.NET 10、C# 14及應用程式開發到2026年,在微服務基礎設施開銷和內部程式庫簡單性之間的選擇對部署和運行複雜性影響甚大。 尋求在保持HTML/CSS/JavaScript渲染保真度的同時減少基礎設施負擔的團隊會發現IronPDF有效地解決了這些需求。
從 免費試用 開始評估 IronPDF,並探索全面的文件以評估特定需求的適用性。
