You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C#在AWS Lambda与API Gateway部署Prince 13.5?

用C#在AWS Lambda + API Gateway部署Prince 13.5指南

一、准备工作

  • 下载Prince 13.5的Linux x86_64版本(Lambda运行在Amazon Linux环境),解压后提取核心执行文件和依赖库
  • 安装.NET 6 SDK(Lambda支持的长期支持版本)
  • 安装AWS Toolkit for Visual Studio(方便快速创建Lambda项目)

二、搭建Lambda函数(C#)

  1. 创建Lambda项目

    • 在Visual Studio中选择「AWS Lambda Project (.NET Core C#)」,模板选「Empty Function」
    • 项目命名示例:PrincePdfGenerator
  2. 整合Prince文件

    • 将Prince的执行文件(prince)和依赖库(lib目录下的所有文件)复制到项目根目录,设置文件属性为「复制到输出目录:始终复制」
    • 注意:Lambda的工作目录无执行权限,必须将Prince文件复制到临时目录/tmp后再执行
  3. 核心代码实现

using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace PrincePdfGenerator
{
    public class Function
    {
        public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
        {
            try
            {
                // 复制Prince文件到/tmp并获取执行路径
                var princeExecPath = CopyPrinceToTempDir();

                // 从API请求Body读取HTML内容
                var htmlContent = request.Body;
                var inputHtmlPath = Path.Combine(Path.GetTempPath(), "input.html");
                File.WriteAllText(inputHtmlPath, htmlContent);

                // 定义输出PDF路径
                var outputPdfPath = Path.Combine(Path.GetTempPath(), "output.pdf");

                // 构造Prince执行命令
                var processStartInfo = new ProcessStartInfo
                {
                    FileName = princeExecPath,
                    Arguments = $"--no-warn {inputHtmlPath} -o {outputPdfPath}",
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                // 执行Prince命令
                using var process = Process.Start(processStartInfo);
                process.WaitForExit();

                if (process.ExitCode != 0)
                {
                    var errorMsg = process.StandardError.ReadToEnd();
                    return new APIGatewayProxyResponse
                    {
                        StatusCode = 500,
                        Body = $"Prince执行失败: {errorMsg}",
                        Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
                    };
                }

                // 读取PDF并返回Base64编码结果
                var pdfBytes = File.ReadAllBytes(outputPdfPath);
                var base64Pdf = Convert.ToBase64String(pdfBytes);

                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = base64Pdf,
                    Headers = new Dictionary<string, string>
                    {
                        { "Content-Type", "application/pdf" },
                        { "Content-Disposition", "attachment; filename=output.pdf" }
                    },
                    IsBase64Encoded = true
                };
            }
            catch (Exception ex)
            {
                return new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = $"服务器错误: {ex.Message}",
                    Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
                };
            }
        }

        private string CopyPrinceToTempDir()
        {
            var tmpDir = Path.GetTempPath();
            var princeExecDest = Path.Combine(tmpDir, "prince");

            // 复制执行文件并赋予执行权限
            if (!File.Exists(princeExecDest))
            {
                var princeExecSrc = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "prince");
                File.Copy(princeExecSrc, princeExecDest);
                Process.Start("chmod", $"+x {princeExecDest}").WaitForExit();
            }

            // 复制依赖库到/tmp/lib
            var libSrcDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lib");
            var libDestDir = Path.Combine(tmpDir, "lib");
            if (!Directory.Exists(libDestDir))
            {
                Directory.CreateDirectory(libDestDir);
                foreach (var file in Directory.GetFiles(libSrcDir))
                {
                    var destFile = Path.Combine(libDestDir, Path.GetFileName(file));
                    if (!File.Exists(destFile)) File.Copy(file, destFile);
                }
            }

            // 设置环境变量让Prince找到依赖库
            Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", $"{libDestDir}:{Environment.GetEnvironmentVariable("LD_LIBRARY_PATH")}");

            return princeExecDest;
        }
    }
}

三、打包部署

  • 在Visual Studio右键项目,选择「Publish to AWS Lambda」
  • 配置Lambda参数:运行时选.NET 6,内存建议设置为1024MB及以上(Prince生成PDF需要较多内存),超时设置为30秒(可根据PDF复杂度调整)
  • 注意:部署包需包含Prince文件,确保压缩后不超过50MB、解压后不超过250MB(Lambda的包大小限制)

四、API Gateway集成

  1. 创建REST API
    • 在AWS控制台的API Gateway中创建REST API,选择「New API」
  2. 添加资源与方法
    • 添加/generate-pdf资源,创建POST方法,集成类型选「Lambda Function」,关联刚才部署的Lambda函数
  3. 配置请求响应
    • 在POST方法的「Integration Request」中,设置「Content Handling」为「Passthrough」
    • 在「Method Response」中,添加200状态码,设置响应头Content-Type为application/pdf、Content-Disposition为attachment; filename=output.pdf
  4. 部署API
    • 创建部署阶段(如prod),获取调用URL即可测试

五、关键技巧

  • 权限处理:Lambda默认拥有/tmp目录的读写权限,无需额外配置
  • 依赖库路径:必须设置LD_LIBRARY_PATH指向/tmp/lib,否则Prince会因找不到依赖库执行失败
  • 资源调优:复杂PDF生成需调高内存和超时时间,可通过CloudWatch日志监控执行情况
  • 日志调试:通过CloudWatch Logs查看Lambda的执行日志,快速定位Prince的报错信息

内容的提问来源于stack exchange,提问作者Steve Shahbazi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:43:15