AWS API Gateway二进制媒体类型映射异常,Lambda无PDF数据求助
问题:API Gateway无法映射application/pdf模板导致Lambda无法获取PDF数据
问题描述
此前正常运行的AWS API Gateway+Lambda PDF上传功能突然失效,API Gateway无法正确映射application/pdf类型的集成模板,导致Lambda无法获取PDF数据。已在API设置中允许application/pdf并配置映射模板,排查无果,附上Terraform脚本:
resource "aws_api_gateway_rest_api" "api_gateway" { name = "api_gateway" description = "API Gateway" binary_media_types = ["application/pdf"] endpoint_configuration { types = ["REGIONAL"] } } resource "aws_api_gateway_account" "infofusion" { cloudwatch_role_arn = aws_iam_role.cloudwatch.arn } data "aws_iam_policy_document" "assume_role" { statement { effect = "Allow" principals { type = "Service" identifiers = ["apigateway.amazonaws.com"] } actions = ["sts:AssumeRole"] } } resource "aws_iam_role" "cloudwatch" { name = "api_gateway_cloudwatch_global" assume_role_policy = data.aws_iam_policy_document.assume_role.json } data "aws_iam_policy_document" "cloudwatch" { statement { effect = "Allow" actions = [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:DescribeLogGroups", "logs:DescribeLogStreams", "logs:PutLogEvents", "logs:GetLogEvents", "logs:FilterLogEvents" ] resources = ["*"] } } resource "aws_iam_role_policy" "cloudwatch" { name = "default" role = aws_iam_role.cloudwatch.id policy = data.aws_iam_policy_document.cloudwatch.json } resource "aws_api_gateway_authorizer" "cognito" { name = "cognito" rest_api_id = aws_api_gateway_rest_api.api_gateway.id type = "COGNITO_USER_POOLS" identity_source = "method.request.header.Authorization" provider_arns = [aws_cognito_user_pool.user_pool.arn] } resource "aws_api_gateway_resource" "pdf" { parent_id = aws_api_gateway_rest_api.api_gateway.root_resource_id path_part = "pdf" rest_api_id = aws_api_gateway_rest_api.api_gateway.id } resource "aws_api_gateway_method" "upload_pdf" { rest_api_id = aws_api_gateway_rest_api.api_gateway.id resource_id = aws_api_gateway_resource.pdf.id request_parameters = { "method.request.querystring.pdfName" = true "method.request.querystring.projectId" = true } http_method = "PUT" authorization = "COGNITO_USER_POOLS" authorizer_id = aws_api_gateway_authorizer.cognito.id } resource "aws_api_gateway_integration" "upload_pdf" { rest_api_id = aws_api_gateway_rest_api.api_gateway.id resource_id = aws_api_gateway_resource.pdf.id http_method = aws_api_gateway_method.upload_pdf.http_method integration_http_method = "POST" type = "AWS" uri = aws_lambda_function.manage_pdf.invoke_arn request_parameters = { "integration.request.querystring.pdfName" = "method.request.querystring.pdfName" "integration.request.querystring.projectId" = "method.request.querystring.projectId" } passthrough_behavior = "WHEN_NO_MATCH" request_templates = { # "application/pdf" = file("${path.module}/resource/apigateway/pdf_upload_mapping_template.vt") # I have a more sophisticated vt but at the moment I just want to get the body first "application/pdf" = <<-EOT { "data": "$input.body" } EOT } } resource "aws_lambda_permission" "pdf_lambda_permission" { statement_id = "AllowAPIInvokeManagePdf" action = "lambda:InvokeFunction" function_name = aws_lambda_function.manage_pdf.function_name principal = "apigateway.amazonaws.com" source_arn = "${aws_api_gateway_rest_api.api_gateway.execution_arn}/*/*". # one doc in tf said /\* and this other /*/*, both stop working }
解决方案与排查点
1. 修正传递行为,强制使用映射模板
当前passthrough_behavior = "WHEN_NO_MATCH"会导致API Gateway对二进制类型跳过模板,直接传递原始数据。修改为:
passthrough_behavior = "NEVER"
确保API Gateway强制使用你配置的application/pdf映射模板处理请求。
2. 正确处理二进制数据的Base64编码
二进制PDF数据无法直接通过JSON传递,需要在映射模板中编码为Base64,修改模板内容:
"application/pdf" = <<-EOT { "data": "$util.base64Encode($input.body)", "pdfName": "$input.params('pdfName')", "projectId": "$input.params('projectId')" } EOT
Lambda端解码data字段即可得到原始PDF字节流。
3. 修复Lambda权限的ARN格式错误
source_arn末尾多了一个句号,修正为:
source_arn = "${aws_api_gateway_rest_api.api_gateway.execution_arn}/*/*"
更严谨的写法可以指定到具体方法,避免权限过宽:
source_arn = "${aws_api_gateway_rest_api.api_gateway.execution_arn}/PUT/pdf"
4. 添加API Gateway部署资源
你的Terraform脚本缺少部署资源,配置修改后不会生效。添加:
resource "aws_api_gateway_deployment" "pdf_upload" { depends_on = [aws_api_gateway_integration.upload_pdf] rest_api_id = aws_api_gateway_rest_api.api_gateway.id stage_name = "prod" # 替换为你的实际阶段名称 }
每次修改API配置后,部署会自动更新生效。
5. 利用CloudWatch日志定位问题
在API Gateway的阶段设置中开启全量日志记录,查看:
- 请求的
Content-Type是否严格为application/pdf - 映射模板是否被正确触发
- 传递到Lambda的请求体内容是否符合预期
内容的提问来源于stack exchange,提问作者Zhengtong Nie
相关产品推荐
相关产品推荐

