如何在不使用 SDK 的情况下将文件从 Android 上传到 Amazon S3

Posted

技术标签:

【中文标题】如何在不使用 SDK 的情况下将文件从 Android 上传到 Amazon S3【英文标题】:How to upload files from Android to Amazon S3 WITHOUT using the SDK 【发布时间】:2013-10-17 08:30:04 【问题描述】:

我一直在努力使用亚马逊 S3 的 REST API 将文件从我的 android 设备上传到我拥有的存储桶中。我有 KEY 和 SECRET_KEY,但不确定如何正确生成他们在请求中寻找的 signatureValue。我在他们的服务器上使用 HttpPut,但不确定如何正确生成 signatureValue。到目前为止,这是我所拥有的:

HttpPut put = new HttpPut(URL);

            String fmt = "EEE, dd MMM yyyy HH:mm:ss ";
            SimpleDateFormat format = new SimpleDateFormat(fmt, Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));

            String method = "PUT";
            String contentType = "application/octet-stream";
            String date = format.format(new Date()) + "GMT";
            String bucket = "/test-bucket52809/";

            StringBuffer buf = new StringBuffer();
            buf.append(method).append("\n\n");
            buf.append(contentType).append("\n");
            buf.append(date).append("\n");
            buf.append(bucket);

            String signature = percentEncodeRfc3986(hmac(buf.toString()));

那么这里是我用来生成签名值的方法:

    private void setupMac() throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException
    

        byte[] secretyKeyBytes = KEY_SECRET.getBytes("UTF-8");
        signingKey = new SecretKeySpec(secretyKeyBytes, "HmacSHA256");
        mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
    

    private String hmac(String stringToSign) 
        String signature = null;
        byte[] data;
        byte[] rawHmac;
        try 
            data = stringToSign.getBytes("UTF-8");
            rawHmac = mac.doFinal(data);
            signature = new String(Base64.encode(rawHmac, Base64.DEFAULT));
         catch (UnsupportedEncodingException e) 
            throw new RuntimeException("UTF-8" + " is unsupported!", e);
        
        return signature;
    

    private String percentEncodeRfc3986(String s) 
        String out;
        try 
            out = URLEncoder.encode(s, "UTF-8").replace("+", "%20")
                    .replace("*", "%2A").replace("%7E", "~");
         catch (UnsupportedEncodingException e) 
            out = s;
        
        return out;
    

我使用了 Amazon S3 签名测试器,我的字符串是正确的,但我从来没有得到正确的编码值。感谢您提供任何帮助或推动正确的方向。

【问题讨论】:

我会看一下 AWS Java SDK 源代码。在github.com/aws/aws-sdk-java 应该很容易找到。 为什么不想使用SDK?它包含许多样板代码来处理签名等,这将避免您处理这些低级细节 您有解决方案吗?我正在尝试在没有 SDK 的情况下上传到 S3。 @sebsto:适用于 Android 的 Amazon SDK 有 20K 方法,这可能会使您超过 Dex 限制。 @user2744821,嗨。您是否在没有 SDK 的情况下上传到 S3?请分享更多代码。 【参考方案1】:
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

String policy = (new BASE64Encoder()).encode(
    policy_document.getBytes("UTF-8")).replaceAll("\n","").replaceAll("\r","");

Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
    aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
    hmac.doFinal(policy.getBytes("UTF-8")))
    .replaceAll("\n", "");

[参考:https://aws.amazon.com/articles/1434]

上面的链接还描述了 HTTP 请求中的输入参数。

【讨论】:

【参考方案2】:

我会仔细检查日期是否符合预期并在 http 标头中发送(您是否设置了“x-amz-date”标头?),在“手动”签署请求时让我有些头疼。

此外,添加来自 S3 的错误消息可能有助于我们了解问题所在并为您提供帮助。

【讨论】:

以上是关于如何在不使用 SDK 的情况下将文件从 Android 上传到 Amazon S3的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用任何付费工具的情况下将 dbf 文件导入 mysql?

如何在不删除源文件的情况下将数据从 HDFS 加载到配置单元?

在不使用 PayPal 按钮的情况下将 PayPal .NET SDK 集成到网站中

如何在没有来自 Kinect Window SDK 的 Coordinatemapper 的情况下将 3D 骨骼关节映射回 2D 彩色图像

我可以在不使用 winformshost 的情况下将 Lync SDK 对话停靠在 WPF 上吗?

如何在不调用 [关闭] 的情况下将整数从控制器设置到子视图