跳至頁尾內容
移民指南

如何在 C# 中將 Gotenberg 遷移到 IronPDF

從 哥登堡 遷移到 IronPDF 會將您的 .NET PDF 工作流程從基於 Docker 的微服務架構和 HTTP API 呼叫轉換為進程內原生 C# 程式庫。 本指南為專業 .NET 開發人員提供了一條全面的、循序漸進的遷移路徑,消除了基礎設施開銷、網路延遲和容器管理複雜性。

為什麼要從 哥登堡 遷移到 IronPDF

哥登堡建築問題

Gotenberg 是一個基於 Docker 的微服務架構,用於產生 PDF 檔案。 雖然功能強大且靈活,但它為 C# 應用程式帶來了顯著的複雜性:

1.基礎架構開銷:需要 Docker、容器編排(Kubernetes/Docker Compose)、服務發現和負載平衡。 每次部署都會變得更加複雜。

2.網路延遲:每次 PDF 操作都需要向單獨的服務發起 HTTP 請求,每次請求會增加 10-100 毫秒以上的延遲。在高流量場景下,這種延遲會迅速累積。

3.冷啟動問題:容器啟動可能會為首次請求增加 2-5 秒的時間。 每次 Pod 重新啟動、每次擴充、每次部署都會觸發冷啟動。

4.操作複雜性:您必須將容器健康狀況、擴充功能、日誌記錄和監控作為與主應用程式分開的獨立問題進行管理。

5.多部分錶單資料:每個請求都需要建立 multipart/form-data 有效負載-冗長、容易出錯且難以維護。

6.故障點:網路逾時、服務不可用和容器崩潰等問題都需要您負責處理。

7.版本管理: 哥登堡 圖片的更新與您的應用程式是分開的; API變更可能會導致整合意外中斷。

哥登堡 與 IronPDF 的比較

方面哥登堡IronPDF
部署Docker容器+編排單一 NuGet 套件
建築學微服務(REST API)行程內庫
每次請求的延遲10-100毫秒以上(網路往返時間)開銷小於 1 毫秒
冷啟動2-5秒(容器初始化)1-2秒(僅限首次渲染)
基礎設施Docker、Kubernetes、負載平衡器無需
故障模式網路、容器、服務故障標準 .NET 異常
API 風格REST multipart/form-data原生 C# 方法調用
規模化水平方向(更多容器)垂直(進行中)
偵錯需要分散式追蹤標準偵錯工具
版本控制容器圖像標籤NuGet 套件版本

對於計劃在 2025 年和 2026 年採用 .NET 10 和 C# 14 的團隊,IronPDF 提供了一個面向未來的基礎架構,它沒有任何基礎設施依賴性,並且可以與現代 .NET 模式原生整合。


遷移複雜度評估

各功能預計工作量

特徵遷移複雜性筆記
HTML 轉 PDF非常低直接替代法
PDF檔案的URL非常低直接替代法
自訂紙張尺寸低的基於屬性的配置
邊際低的單位換算(英吋→毫米)
PDF合併低的靜態方法調用
頁首/頁尾中等的不同的佔位符語法
等待延遲低的將字串轉換為毫秒
PDF/A 轉換低的方法呼叫而非參數

範式轉移

Gotenberg 遷移的根本轉變在於從使用 multipart 表單資料的 HTTP API 呼叫轉變原生 C# 方法呼叫:

哥登堡:透過 HTTP POST multipart/form-data 向 Docker 容器發送請求
IronPDF:直接呼叫 C# 物件的方法

開始之前

先決條件

  1. .NET 版本: IronPDF 支援 .NET Framework 4.6.2+ 和 .NET Core 3.1+ / .NET 5/6/7/8/9+ 2.許可證密鑰:ironpdf.com取得您的 IronPDF 許可證密鑰。 3.規劃基礎設施移除:記錄哥登堡容器在遷移後的退役事宜

識別所有哥德堡用法

# Find direct HTTP calls to Gotenberg
grep -r "gotenberg\|/forms/chromium\|/forms/libreoffice\|/forms/pdfengines" --include="*.cs" .

# Find GotenbergSharpApiClient usage
grep -r "GotenbergSharpClient\|Gotenberg.Sharp\|ChromiumRequest" --include="*.cs" .

# Find Docker/Kubernetes 哥登堡 configuration
grep -r "gotenberg/gotenberg\|gotenberg:" --include="*.yml" --include="*.yaml" .
# Find direct HTTP calls to Gotenberg
grep -r "gotenberg\|/forms/chromium\|/forms/libreoffice\|/forms/pdfengines" --include="*.cs" .

# Find GotenbergSharpApiClient usage
grep -r "GotenbergSharpClient\|Gotenberg.Sharp\|ChromiumRequest" --include="*.cs" .

# Find Docker/Kubernetes 哥登堡 configuration
grep -r "gotenberg/gotenberg\|gotenberg:" --include="*.yml" --include="*.yaml" .
SHELL

NuGet 套件變更

# Remove 哥登堡 client (if using)
dotnet remove package Gotenberg.Sharp.API.Client

# Install IronPDF
dotnet add package IronPdf
# Remove 哥登堡 client (if using)
dotnet remove package Gotenberg.Sharp.API.Client

# Install IronPDF
dotnet add package IronPdf
SHELL

快速入門遷移

步驟 1:更新許可證配置

之前(哥德堡):

Gotenberg 不需要許可證,但需要帶有容器 URL 的 Docker 基礎架構。

private readonly string _gotenbergUrl = "http://localhost:3000";
private readonly string _gotenbergUrl = "http://localhost:3000";
$vbLabelText   $csharpLabel

(IronPDF 之後):

// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
$vbLabelText   $csharpLabel

步驟 2:更新命名空間導入

// Before (Gotenberg)
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
// Before (Gotenberg)
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
$vbLabelText   $csharpLabel

完整 API 參考

哥登堡端點到 IronPDF 映射

哥德堡路線IronPDF當量筆記
POST /forms/chromium/convert/htmlChromePdfRenderer.RenderHtmlAsPdf()將 HTML 字串轉換為 PDF
POST /forms/chromium/convert/urlChromePdfRenderer.RenderUrlAsPdf()PDF檔案的URL
POST /forms/pdfengines/mergePdfDocument.Merge()合併多個PDF文件
POST /forms/pdfengines/convert使用設定呼叫pdf.SaveAs()PDF/A 轉換
GET /health不適用無需外部服務

表單參數到渲染選項的映射

哥登堡參數IronPDF屬性轉換票據
paperWidth (英吋)RenderingOptions.PaperSize使用枚舉或自訂大小
paperHeight (英吋)RenderingOptions.PaperSize使用枚舉或自訂大小
marginTop (吋)RenderingOptions.MarginTop乘以 25.4 得到毫米
marginBottom (英吋)RenderingOptions.MarginBottom乘以 25.4 得到毫米
printBackgroundRenderingOptions.PrintHtmlBackgrounds布林值
landscapeRenderingOptions.PaperOrientationLandscape枚舉
waitDelayRenderingOptions.RenderDelay轉換為毫秒

程式碼遷移範例

範例 1:基本 HTML 轉 PDF

之前(哥德堡):

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");
    }
}
$vbLabelText   $csharpLabel

(IronPDF 之後):

// 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");
    }
}
$vbLabelText   $csharpLabel

差異很大:Gotenberg 需要建置HttpClient ,建置MultipartFormDataContent ,向正在執行的 Docker 容器發出非同步 HTTP POST 請求,並處理位元組陣列回應。 IronPDF 將其簡化為三行程式碼,透過ChromePdfRenderer方法呼叫實現——沒有網路開銷,沒有容器依賴,沒有非同步複雜性。 有關其他渲染選項,請參閱HTML 轉 PDF 文件

範例 2:URL 轉 PDF

之前(哥德堡):

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");
    }
}
$vbLabelText   $csharpLabel

(IronPDF 之後):

// 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");
    }
}
$vbLabelText   $csharpLabel

Gotenberg 方法需要一個不同的端點( /forms/chromium/convert/url ),使用 URL 作為表單欄位建立多部分內容,並處理非同步 HTTP 回應。 IronPDF 的RenderUrlAsPdf()方法直接接受 URL,並同步回傳一個PdfDocument物件。 了解更多關於URL轉PDF的資訊

範例 3:自訂紙張尺寸和邊距

之前(哥德堡):

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");
    }
}
$vbLabelText   $csharpLabel

(IronPDF 之後):

// 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");
    }
}
$vbLabelText   $csharpLabel

Gotenberg 要求在 multipart 表單資料中加入基於字串的參數( &quot;8.5&quot;&quot;11&quot;&quot;0.5&quot; ),沒有型別安全,沒有 IntelliSense,容易輸入錯誤。 IronPDF 提供具有PdfPaperSize枚舉和數值邊距值的強型別屬性。 請注意,IronPDF 的邊距單位是毫米(50 毫米 ≈ 2 英吋),而 哥登堡 使用英吋。


關鍵遷移說明

單位換算

哥登堡遷移中最重要的轉換是邊距單位:

// Gotenberg: margins in inches
content.Add(new StringContent("0.5"), "marginTop");    // 0.5 inches
content.Add(new StringContent("1"), "marginBottom");   // 1 inch

// IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7;    // 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4; // 1 inch × 25.4 = 25.4mm
// Gotenberg: margins in inches
content.Add(new StringContent("0.5"), "marginTop");    // 0.5 inches
content.Add(new StringContent("1"), "marginBottom");   // 1 inch

// IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7;    // 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4; // 1 inch × 25.4 = 25.4mm
$vbLabelText   $csharpLabel

換算公式: millimeters = inches × 25.4

同步與非同步

由於 哥登堡 使用 HTTP 通信,因此需要非同步操作:

// Gotenberg: Forced async due to network calls
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();

// IronPDF: Synchronous in-process execution
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

// IronPDF: Async wrapper if needed
var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(html));
// Gotenberg: Forced async due to network calls
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();

// IronPDF: Synchronous in-process execution
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

// IronPDF: Async wrapper if needed
var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(html));
$vbLabelText   $csharpLabel

錯誤處理

// Gotenberg: HTTP error handling
try
{
    var response = await client.PostAsync(gotenbergUrl, content);
    response.EnsureSuccessStatusCode();  // What if 500? 503? Timeout?
}
catch (HttpRequestException ex) { /* Network error */ }
catch (TaskCanceledException ex) { /* Timeout */ }

// IronPDF: Standard .NET exceptions
try
{
    var pdf = renderer.RenderHtmlAsPdf(html);
}
catch (Exception ex)
{
    Console.WriteLine($"PDF generation failed: {ex.Message}");
}
// Gotenberg: HTTP error handling
try
{
    var response = await client.PostAsync(gotenbergUrl, content);
    response.EnsureSuccessStatusCode();  // What if 500? 503? Timeout?
}
catch (HttpRequestException ex) { /* Network error */ }
catch (TaskCanceledException ex) { /* Timeout */ }

// IronPDF: Standard .NET exceptions
try
{
    var pdf = renderer.RenderHtmlAsPdf(html);
}
catch (Exception ex)
{
    Console.WriteLine($"PDF generation failed: {ex.Message}");
}
$vbLabelText   $csharpLabel

基礎設施拆除

遷移完成後,請從您的基礎架構中移除 Gotenberg:

# REMOVE from docker-compose.yml:
# services:
#   gotenberg:
#     image: gotenberg/gotenberg:8
#     ports:
#       - "3000:3000"
#     deploy:
#       resources:
#         limits:
#           memory: 2G
# REMOVE from docker-compose.yml:
# services:
#   gotenberg:
#     image: gotenberg/gotenberg:8
#     ports:
#       - "3000:3000"
#     deploy:
#       resources:
#         limits:
#           memory: 2G
YAML

性能考量

延遲比較

手術哥登堡(溫暖)哥登堡(冷啟動)IronPDF(初稿)IronPDF(後續)
簡單的 HTML150-300毫秒2-5秒1-2秒50-150毫秒
複雜的 HTML500-1500毫秒3-7秒1.5-3秒200-800毫秒
URL渲染1-5秒3-10秒1-5秒500毫秒-3秒

基礎設施成本消除

資源哥登堡IronPDF
所需容器1-N(縮放)0
每個容器的內存512MB-2GB不適用
每個請求的網路開銷10-100毫秒0毫秒
健康檢查終點必需的不需要
負載平衡器經常需要不需要

故障排除

問題 1:無需使用 HttpClient 模式

問題:程式碼仍然使用HttpClientMultipartFormDataContent

解決方案:完全替換為ChromePdfRenderer

// Remove all of this:
// using var client = new HttpClient();
// using var content = new MultipartFormDataContent();
// content.Add(new StringContent(html), "files", "index.html");
// var response = await client.PostAsync(url, content);

// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Remove all of this:
// using var client = new HttpClient();
// using var content = new MultipartFormDataContent();
// content.Add(new StringContent(html), "files", "index.html");
// var response = await client.PostAsync(url, content);

// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
$vbLabelText   $csharpLabel

問題 2:利潤單位錯誤

問題:遷移後 PDF 檔案的邊距不正確。

解決方法:將英吋轉換為毫米:

// 哥登堡 used inches: "0.5"
// IronPDF uses millimeters: 0.5 × 25.4 = 12.7
renderer.RenderingOptions.MarginTop = 12.7;
// 哥登堡 used inches: "0.5"
// IronPDF uses millimeters: 0.5 × 25.4 = 12.7
renderer.RenderingOptions.MarginTop = 12.7;
$vbLabelText   $csharpLabel

問題 3:容器 URL 引用

問題:程式碼包含http://gotenberg:3000或類似 URL。

解決方案:移除所有容器 URL 引用-IronPDF 以進程內方式執行:

// Remove:
// private readonly string _gotenbergUrl = "http://gotenberg:3000";

// IronPDF needs no URL - it's in-process
var renderer = new ChromePdfRenderer();
// Remove:
// private readonly string _gotenbergUrl = "http://gotenberg:3000";

// IronPDF needs no URL - it's in-process
var renderer = new ChromePdfRenderer();
$vbLabelText   $csharpLabel

遷移清單

遷移前

  • 清點程式碼庫中所有 哥登堡 HTTP 調用
  • 記錄目前 哥登堡 配置(逾時、頁邊距、紙張尺寸)
  • 識別所有 Docker/Kubernetes 哥登堡 配置
  • 取得 IronPDF 許可證密鑰
  • 規劃基礎建設退役

程式碼遷移

安裝 IronPdf NuGet 套件: dotnet add package IronPdf

  • 移除 哥登堡 用戶端軟體包
  • 將所有對 哥登堡 的 HTTP 呼叫替換為 IronPDF 方法調用
  • 將邊距單位從英吋轉換為毫米
  • 更新錯誤處理(HTTP 錯誤 → .NET 異常)
  • 新增啟動時許可證金鑰初始化功能

基礎設施遷移

  • 從 Docker Compose/Kubernetes 移除 Gotenberg
  • 更新 CI/CD 管線(移除 哥登堡 鏡像拉取)
  • 移除哥德堡健康檢查
  • 從設定中移除 哥登堡 URL

測試

  • 測試 HTML 到 PDF 的轉換
  • 測試 URL 到 PDF 的轉換
  • 核實邊距和尺寸準確性
  • 負載下的效能測試
  • 測試首次渲染預熱時間

移民後

  • 移除 哥登堡 容器部署
  • 歸檔 哥登堡 設定檔
  • 更新文檔
  • 監控應用程式記憶體使用情況
  • 檢查是否有孤立的網路連接

柯蒂斯·週
技術撰稿人

Curtis Chau擁有卡爾頓大學電腦科學學士學位,專長於前端開發,精通Node.js、TypeScript、JavaScript和React。他熱衷於打造直覺美觀的使用者介面,喜歡使用現代框架,並擅長撰寫結構清晰、視覺效果出色的使用者手冊。

除了開發工作之外,柯蒂斯對物聯網 (IoT) 也抱有濃厚的興趣,致力於探索硬體和軟體整合的創新方法。閒暇時,他喜歡玩遊戲和製作 Discord 機器人,將他對科技的熱愛與創造力結合。