如何在 Lambda 和 vice-versa 中处理来自 API 网关的二进制数据?
How to process binary data from API Gateway in Lambda and vice-versa?
我目前有以下设置:
1. S3 桶
2. API 具有 GET/POST 资源的网关
3. 两个Lambda函数(一个从s3取数据,一个存数据到s3)
例如 GET 资源,我传递了一个关键参数,它在 lambda 函数中用于从 s3 存储桶中获取 object。然后我想 return 检索到 object 到 api 网关和客户端作为二进制文件。
在 POST 资源中,我想发送二进制负载,例如:pdf 或 zip 文件,将其保存到 s3 和 return 生成的密钥。
所以一方面我希望我的 api 网关和 lambda 能够在 GET 请求中 return 二进制数据,另一方面我希望它在 POST 中接受二进制有效载荷] 请求。
在 api 网关设置中,我已将 Binary-Media-Types 设置为 application/octet-stream
。我还激活了 lambda 代理集成。
我的问题是:如何处理 api gateway/lambda 中的二进制数据?
我试着摆弄 Headers 和 Content-Types 但或多或少我不知道我在做什么 :(
示例 store-luggage 用于在 S3 中存储来自 POST 请求的数据的 lambda
import boto3
import json
import uuid
import logging
from botocore.exceptions import ClientError
def lambda_handler(event, context):
#data = <binary data from POST request>?
logger = logging.getLogger()
logger.setLevel(logging.INFO)
bucket = 'bucket1'
uniqueid = str(uuid.uuid4())
logger.info("Generated UUID: " + uniqueid)
s3 = boto3.resource('s3')
logger.info("Trying to save file '" + uniqueid + "' to bucket '" + bucket + "'")
savedObj = None
try:
savedObj = s3.Bucket(bucket).put_object(Key=uniqueid, Body=<here should be my binary payload from POST request>)
except ClientError as e:
logger.error("Saving of object has failed: " + str(e.response['Error']['Message']))
if savedObj is None:
return {
'statusCode': 500,
'body': json.dumps({
'message': 'Saving of object has failed!'
})
}
return {
'statusCode': 200,
'body': json.dumps({
'token': uniqueid
})
}
get-luggage 用于通过给定密钥从 s3 检索 object 的 lambda 和响应中的 return 二进制负载
import boto3
import json
from pprint import pprint
from botocore.exceptions import ClientError
import logging
def lambda_handler(event, context):
logger = logging.getLogger()
logger.setLevel(logging.INFO)
bucket = 'bucket1'
token = event["queryStringParameters"]["token"]
s3 = boto3.client('s3')
objectFromS3 = None
try:
objectFromS3 = s3.get_object(Bucket=bucket, Key=token)
except ClientError as ex:
if ex.response['Error']['Code'] == 'NoSuchKey':
logger.info('No object found - returning empty')
else:
raise ex
if objectFromS3 is None:
return {
'statusCode': 404,
'body': json.dumps({
'message': 'Cannot retrieve object from storage!'
})
}
pprint(objectFromS3)
#ContentType application/octet-stream
return {
'statusCode': 200,
'body' : <binary data from retrieved s3 object here?>,
'headers': {
'content-type': 'application/octet-stream'
},
'isBase64Encoded': True
}
我希望在 GET 响应中检索二进制负载,并希望 api 网关将二进制负载从 POST 请求传递到 lambda,但是 none 这是通过我的东西实现的试过了。
我希望我对我的问题的描述足够好,如果需要任何澄清,请告诉我。
最良好的祝愿,
aws 新手
首先,您需要在 API 网关设置中配置您希望将其视为二进制数据的 MIME 类型。
Settings -> Binary Media Types.
指定要用作二进制数据的确切 MIME 类型 application/pdf、application/zip 等。application/octet-stream 表示确切类型未知的通用数据。
在您的 Http 请求中,应该有 Accept header 指示负载中包含哪种 MIME 类型。
接受:application/pdf
接受:application/zip
由于 AWS Lambda 以 base64 编码处理请求和响应,您应该解码 POST 请求 body 并在上传到 S3 存储桶之前获取原始二进制内容。
从 S3 存储桶中获取数据后,lambda 在将二进制数据发送到 API 网关之前对其进行编码。作为响应,您应该将 isBase64Encoded 标志的值设置为 True。然后API网关对编码后的数据进行Base64解码再发送给客户端如果Http请求包含相应的Acceptheader.
get-luggage:
如果您的文件已经在 S3 中,您可以通过在 API-Gateway headers 上添加 Location
属性将用户重定向到 S3 中的文件 link,减少网关数据流量。
示例:
exports.handler = (event, context, callback) => {
return callback(null, {
statusCode: 301,
headers: {
Location: 'https://<...S3...>',
}
});
}
在方法请求 > HTTP 请求 Headers 提交 "Accept: application/pdf" 是不可能的,因为它 returns 错误,"Invalid patch path /requestParameters/method.request.header.Accept: application/pdf."
对于我自己,我有以下 Lambda:
import boto3
import base64
def lambda_handler(event, context):
s3 = boto3.client("s3")
fileObj = s3.get_object(Bucket="mytestbucket", Key="sample.pdf")
file_content = fileObj["Body"].read()
return {
"statusCode": 200,
"headers": {"Content-Type":"application/pdf"},
"body": base64.b64encode(file_content),
"isBase64Encoded": True
}
但是响应 body 是 base64 编码的,而不是 sample.pdf 文件本身。是的,我在 API 网关控制台的设置中将 */* 设置为二进制媒体类型。有什么建议我可能遗漏了什么吗?
我目前有以下设置: 1. S3 桶 2. API 具有 GET/POST 资源的网关 3. 两个Lambda函数(一个从s3取数据,一个存数据到s3)
例如 GET 资源,我传递了一个关键参数,它在 lambda 函数中用于从 s3 存储桶中获取 object。然后我想 return 检索到 object 到 api 网关和客户端作为二进制文件。
在 POST 资源中,我想发送二进制负载,例如:pdf 或 zip 文件,将其保存到 s3 和 return 生成的密钥。
所以一方面我希望我的 api 网关和 lambda 能够在 GET 请求中 return 二进制数据,另一方面我希望它在 POST 中接受二进制有效载荷] 请求。
在 api 网关设置中,我已将 Binary-Media-Types 设置为 application/octet-stream
。我还激活了 lambda 代理集成。
我的问题是:如何处理 api gateway/lambda 中的二进制数据?
我试着摆弄 Headers 和 Content-Types 但或多或少我不知道我在做什么 :(
示例 store-luggage 用于在 S3 中存储来自 POST 请求的数据的 lambda
import boto3
import json
import uuid
import logging
from botocore.exceptions import ClientError
def lambda_handler(event, context):
#data = <binary data from POST request>?
logger = logging.getLogger()
logger.setLevel(logging.INFO)
bucket = 'bucket1'
uniqueid = str(uuid.uuid4())
logger.info("Generated UUID: " + uniqueid)
s3 = boto3.resource('s3')
logger.info("Trying to save file '" + uniqueid + "' to bucket '" + bucket + "'")
savedObj = None
try:
savedObj = s3.Bucket(bucket).put_object(Key=uniqueid, Body=<here should be my binary payload from POST request>)
except ClientError as e:
logger.error("Saving of object has failed: " + str(e.response['Error']['Message']))
if savedObj is None:
return {
'statusCode': 500,
'body': json.dumps({
'message': 'Saving of object has failed!'
})
}
return {
'statusCode': 200,
'body': json.dumps({
'token': uniqueid
})
}
get-luggage 用于通过给定密钥从 s3 检索 object 的 lambda 和响应中的 return 二进制负载
import boto3
import json
from pprint import pprint
from botocore.exceptions import ClientError
import logging
def lambda_handler(event, context):
logger = logging.getLogger()
logger.setLevel(logging.INFO)
bucket = 'bucket1'
token = event["queryStringParameters"]["token"]
s3 = boto3.client('s3')
objectFromS3 = None
try:
objectFromS3 = s3.get_object(Bucket=bucket, Key=token)
except ClientError as ex:
if ex.response['Error']['Code'] == 'NoSuchKey':
logger.info('No object found - returning empty')
else:
raise ex
if objectFromS3 is None:
return {
'statusCode': 404,
'body': json.dumps({
'message': 'Cannot retrieve object from storage!'
})
}
pprint(objectFromS3)
#ContentType application/octet-stream
return {
'statusCode': 200,
'body' : <binary data from retrieved s3 object here?>,
'headers': {
'content-type': 'application/octet-stream'
},
'isBase64Encoded': True
}
我希望在 GET 响应中检索二进制负载,并希望 api 网关将二进制负载从 POST 请求传递到 lambda,但是 none 这是通过我的东西实现的试过了。
我希望我对我的问题的描述足够好,如果需要任何澄清,请告诉我。
最良好的祝愿, aws 新手
首先,您需要在 API 网关设置中配置您希望将其视为二进制数据的 MIME 类型。
Settings -> Binary Media Types.
指定要用作二进制数据的确切 MIME 类型 application/pdf、application/zip 等。application/octet-stream 表示确切类型未知的通用数据。
在您的 Http 请求中,应该有 Accept header 指示负载中包含哪种 MIME 类型。
接受:application/pdf
接受:application/zip
由于 AWS Lambda 以 base64 编码处理请求和响应,您应该解码 POST 请求 body 并在上传到 S3 存储桶之前获取原始二进制内容。
从 S3 存储桶中获取数据后,lambda 在将二进制数据发送到 API 网关之前对其进行编码。作为响应,您应该将 isBase64Encoded 标志的值设置为 True。然后API网关对编码后的数据进行Base64解码再发送给客户端如果Http请求包含相应的Acceptheader.
get-luggage:
如果您的文件已经在 S3 中,您可以通过在 API-Gateway headers 上添加 Location
属性将用户重定向到 S3 中的文件 link,减少网关数据流量。
示例:
exports.handler = (event, context, callback) => {
return callback(null, {
statusCode: 301,
headers: {
Location: 'https://<...S3...>',
}
});
}
在方法请求 > HTTP 请求 Headers 提交 "Accept: application/pdf" 是不可能的,因为它 returns 错误,"Invalid patch path /requestParameters/method.request.header.Accept: application/pdf."
对于我自己,我有以下 Lambda:
import boto3
import base64
def lambda_handler(event, context):
s3 = boto3.client("s3")
fileObj = s3.get_object(Bucket="mytestbucket", Key="sample.pdf")
file_content = fileObj["Body"].read()
return {
"statusCode": 200,
"headers": {"Content-Type":"application/pdf"},
"body": base64.b64encode(file_content),
"isBase64Encoded": True
}
但是响应 body 是 base64 编码的,而不是 sample.pdf 文件本身。是的,我在 API 网关控制台的设置中将 */* 设置为二进制媒体类型。有什么建议我可能遗漏了什么吗?