使用Micronaut创建返回二进制内容的AWS Lambda函数
Micronaut Lambda + API Gateway 返回PDF文件解决方案
没问题,这种场景完全是支持的!你遇到的Content-Type始终是application/json的问题,主要是因为API Gateway未配置二进制媒体类型,再加上Micronaut默认会把byte[]序列化成JSON数组导致的。结合你用Groovy+Dynamic Reports+DynamoDB的需求,下面给你一步步梳理解决步骤:
一、先配置AWS API Gateway支持二进制PDF
API Gateway默认只会把application/json等少数类型当作文本处理,要返回PDF必须先添加对应的二进制媒体类型:
- 如果你用的是REST API(API Gateway v1):
- 登录AWS控制台,进入API Gateway服务,找到你的目标API
- 切换到「Settings」标签页,在「Binary Media Types」区域点击「Add binary media type」,输入
application/pdf后保存 - 重新部署你的API(这点很重要,配置变更需要部署才会生效)
- 如果你用的是HTTP API(API Gateway v2):
- 进入目标HTTP API的「Settings」页面
- 在「Binary media types」里添加
application/pdf - 确保「Payload format version」设置为
2.0,这个版本对二进制内容的处理更友好
二、调整Micronaut Groovy代码,正确构建响应
直接返回byte[]时,Micronaut会默认把它序列化成JSON数组,所以我们需要手动构建HTTP响应,指定正确的Content-Type和二进制内容:
import io.micronaut.http.HttpResponse import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Get import net.sf.dynamicreports.jasper.builder.JasperReportBuilder import static net.sf.dynamicreports.report.builder.DynamicReports.* @Controller("/reports") class PdfReportController { @Get("/download") HttpResponse<byte[]> generatePdfReport() { // 1. 从DynamoDB获取数据(这里替换成你的实际查询逻辑) def reportData = fetchDataFromDynamoDB() // 2. 用Dynamic Reports生成PDF字节数组 byte[] pdfBytes = buildPdfReport(reportData) // 3. 构建正确的HTTP响应 return HttpResponse.ok(pdfBytes) .contentType("application/pdf") // 可选:添加Content-Disposition,让浏览器直接下载或预览 .header("Content-Disposition", "inline; filename=dynamodb-report.pdf") } private List<Map<String, Object>> fetchDataFromDynamoDB() { // 你的DynamoDB数据查询逻辑,比如用AWS SDK for Groovy // 示例伪代码: // def dynamoDb = AmazonDynamoDBClientBuilder.defaultClient() // def scanResult = dynamoDb.scan(new ScanRequest().withTableName("YourTable")) // return scanResult.items [] // 替换成实际数据 } private byte[] buildPdfReport(List<Map<String, Object>> data) { def outputStream = new ByteArrayOutputStream() JasperReportBuilder report = report() .columns( col.column("ID", "id", type.stringType()), col.column("Name", "name", type.stringType()) // 根据你的数据添加更多列 ) .title(cmp.text("DynamoDB Data Report")) .pageFooter(cmp.pageXofY()) .setDataSource(data) report.toPdf(outputStream) return outputStream.toByteArray() } }
三、Lambda Handler配置确认
确保你的Lambda函数使用Micronaut官方的Lambda代理适配器,即把handler设置为:
io.micronaut.function.aws.proxy.MicronautLambdaHandler
这个适配器会正确处理Micronaut的HTTP响应,并把二进制内容传递给API Gateway。
额外注意事项
- 如果用Serverless Framework或AWS SAM部署,记得在部署模板里配置二进制媒体类型,比如SAM模板示例:
Resources: PdfReportApi: Type: AWS::Serverless::Api Properties: BinaryMediaTypes: - application/pdf StageName: prod PdfReportFunction: Type: AWS::Serverless::Function Properties: Handler: io.micronaut.function.aws.proxy.MicronautLambdaHandler Runtime: java17 # 对应你的Micronaut支持的Java版本 Events: ApiEvent: Type: Api Properties: RestApiId: !Ref PdfReportApi Path: /reports/download Method: get
- 测试时,确保请求的
Accept头设置为application/pdf,这样API Gateway会直接返回二进制PDF,而不是Base64编码的字符串 - 本地测试时,可以先单独验证Dynamic Reports生成的PDF字节数组是否正确,比如保存到本地文件打开确认
内容的提问来源于stack exchange,提问作者J. Snook
相关产品推荐
相关产品推荐

