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+barfoo%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/urlurl.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 SNS设置有关上传事件的AWS S3?

如何使用 AWS 胶水获取存储在 s3 中的模式或已处理的嵌套 json 文件压缩(gzip)?

AWS S3 CLI - 如何使用存储桶上设置的所有当前策略获取 JSON?

在 AWS Athena 中查询第一个非空值的动态 JSON 字段

如何在删除空S3 Elastic Beanstalk时修复“拒绝访问”?

json AWS S3 Bucket策略#aws#aws-s3