AWS:如何修复 S3 事件用“+”在 json 中登录对象键名替换空格
Posted
技术标签:
【中文标题】AWS:如何修复 S3 事件用“+”在 json 中登录对象键名替换空格【英文标题】:AWS: how to fix S3 event replacing space with '+' sign in object key names in json 【发布时间】:2017-11-30 10:25:22 【问题描述】:我有一个lamba函数将对象从存储桶'A'复制到存储桶'B',一切正常,直到在存储桶'A'中创建名为'New Text Document.txt'的对象,json在 S3 事件中构建,键为“key”:“New+Text+Document.txt”。
空格已替换为“+”。我知道这是一个通过网络搜索的已知问题。 但我不确定如何解决这个问题,传入的 json 本身有一个“+”,而“+”实际上可以在文件名中。像'New+Text Document.txt'。
所以我不能盲目地在我的 lambda 函数中将 '+' 与 ' ' 隔开。
由于这个问题,当代码尝试在存储桶中查找文件时,它无法找到它。
请提出建议。
【问题讨论】:
如果您将名称表示为 html url,您可以避免这种“冲突”:空格变成%20
和 + 变成 %2B
?然后,您可以将其转换回真实角色。
感谢@LoneWanderer,但这是我从 S3 put 事件中获得的 json 值。
知道了,但我认为你搞砸了......如果你必须通过打开一个文件来找出真正的文件名来尝试+
和` `的所有组合,你可以惹麻烦了……你不能在文件名中禁止+
吗?听起来很暴力,但是嘿...
@LoneWanderer 在 S3 的 internal 对象键表示中存在一个根深蒂固的错误,可能是 SOAP 保留。 %20
和 +
在PUT
URI 中都 在内部存储为字符+
。 URI 中的两个符号都表示 ASCII 32... 同时,%2B
存储为%2B
,即使没有浏览器会在路径中将+
转义为%2B
(这应该只发生在查询字符串中) .如果您上传一个名为foo+bar
或 foo%20bar
的文件,您实际上可以下载与foo+bar
或foo%20bar
相同的文件。那是同一个对象。
如果我的文件以加号和空格命名,该怎么办?
【参考方案1】:
我在寻找用 python 而不是 java 编写的 lambda 的解决方案时遇到了这个问题; “urllib.parse.unquote_plus”对我有用,它正确处理了一个带有空格和 + 符号的文件:
from urllib.parse import unquote_plus
import boto3
bucket = 'testBucket1234'
# uploaded file with name 'foo + bar.txt' for test, s3 Put event passes following encoded object_key
object_key = 'foo %2B bar.txt'
print(object_key)
object_key = unquote_plus(object_key)
print(object_key)
client = boto3.client('s3')
client.get_object(Bucket=bucket, Key=object_key)
【讨论】:
谢谢。正是我想要的。【参考方案2】:我为解决这个问题所做的是
java.net.URLDecoder.decode(b.getS3().getObject().getKey(), "UTF-8")
"Records": [
"s3":
"object":
"key": "New+Text+Document.txt"
]
所以现在 JSon 值“New+Text+Document.txt”被正确地转换为 New Text Document.txt。
这已经解决了我的问题,如果这是非常正确的解决方案,请提出建议。 是否有任何极端情况会破坏我的实施。
【讨论】:
这应该是正确的解决方案。除非java.net.URLDecoder.decode()
没有以预期/合理的方式处理边缘/角落情况,否则您的解决方案似乎完全正确。
问题是1."New+Text+Document.txt"和2."New Text Document.txt",和3."New Text+Document.txt"在事件(键:“New+Text+Document.txt”)。您的代码将在案例 1 和 3 中失败。
golang 中的相同问题,已使用来自 net/url
的 url.QueryUnescape(s3key)
修复
@ArielAraza 解码有效,因为发送给 lambda 的密钥已经被 Url 编码。对于名为“my file with spaces + and plus test.csv”的文件,发送到 lambda 的键是“my+file+with+spaces+%2B+and+plus+test.csv”。 (注意“+”被替换为“%2B”。)【参考方案3】:
NodeJS、javascript 或 Typescript
由于我们是为其他运行时共享的,所以这里是如何在 NodeJS 中进行的:
const srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
我会说这是一个官方解决方案,因为它来自AWS docs here
【讨论】:
【参考方案4】:我认为在 Java 中你应该使用:
getS3().getObject().getUrlDecodedKey()
返回解码密钥的方法,而不是
getS3().getObject().getKey()
【讨论】:
他描述的问题并导致我来到这里的是 lambda 'create object' 事件触发器是包含空格的 + 的内容,这意味着您还没有对象,因为键(如事件返回)与存储桶中的任何对象都不匹配。 我的问题与问题完全相同。此解决方案使用 Object 中可用的本机方法解决了该问题 - 简单而优雅。它返回没有编码的密钥。后续的getObject操作成功找到文件key,将文件从Bucket A移动到Bucket B。【参考方案5】:在 ASP.Net 中有 UrlDecode。示例如下。
HttpUtility.UrlDecode(s3entity.Object.Key, Encoding.UTF8)
【讨论】:
【参考方案6】:同意斯科特的观点。对我来说,创建对象事件为分号附加了 %3:我必须替换它两次才能获得正确的 s3 url
Python 代码:
def lambda_handler(event, context):
logger.info('Event: %s' % json.dumps(event))
source_bucket = event['Records'][0]['s3']['bucket']['name']
key_old = event['Records'][0]['s3']['object']['key']
key_new = key_old.replace('%3',':')
key = key_new.replace(':A',':')
logger.info('key value')
logger.info(key)
【讨论】:
【参考方案7】:我遇到了与特殊字符相同的问题,因为 aws S3 事件替换了 UrlEncoding 中的特殊字符。所以为了解决同样的问题,我使用了 aws decode API "SdkHttpUtils.urlDecode(String key)" 来解码对象键。因此按预期工作。
您可以查看以下链接以获取有关 SdkHttpUtils API 的更多详细信息。
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/util/SdkHttpUtils.html#urlDecode-java.lang.String-
【讨论】:
以上是关于AWS:如何修复 S3 事件用“+”在 json 中登录对象键名替换空格的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 AWS 胶水获取存储在 s3 中的模式或已处理的嵌套 json 文件压缩(gzip)?
AWS S3 CLI - 如何使用存储桶上设置的所有当前策略获取 JSON?
在 AWS Athena 中查询第一个非空值的动态 JSON 字段