AWS 签名 URL 在除 Android 以外的任何地方都有效
AWS signed URLs working everywhere except Android
我正在使用 AWS Lambda 为我的移动产品创建一个简单的上传服务。
在服务器上,我使用以下代码
生成预签名URL
var params = {
Bucket: targetS3Bucket,
Key: key,
Body: '',
ContentType: event.contentType,
Expires: 60
};
s3.getSignedUrl('putObject', params, function (err, url){
context.done(null, {
'oneTimeUploadUrl': url,
'resultUrl': urlPrefix + key
});
});
其中 targetS3Bucket
是 S3 上文件夹的路径,key
是文件本身的名称,urlPrefix
是 S3 上文件的 HTTP 位置的根目录(即:s3.amazonaws.com/some-folder/
)
将此代码与内置 HTTP 库一起使用(也就是说,不使用任何 aws SDK)在 PC 和 iOS 上都可以正常工作,但是不在 Android.
最新版本的 Android 客户端代码如下所示:
uri = new URL(oneTimeUploadUrl);
// Setup Connection
HttpsURLConnection http = (HttpsURLConnection) uri.openConnection();
http.setDoOutput(true);
http.setRequestMethod("PUT");
// Write Data
OutputStream os = http.getOutputStream();
os.write(_bytes);
os.flush();
os.close(); // request gets sent off to the server
这一直失败,代码为 400
。我尝试了几种方法,例如更改编码、使用 HttpsURLConnection
的非 https 版本和其他一些方法,但无济于事。
我宁愿避免引入 AWS SDK,因为我只需要这个单一功能即可工作,并且使用这个 lambada 端解决方案可以在除 android.[=20 之外的所有平台上使用=]
这是从 AWS 返回的 XML。返回的消息令人困惑,因为客户端从不更改令牌,并且相同的过程在其他设备上成功。
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidToken</Code>
<Message>The provided token is malformed or otherwise invalid.</Message>
<Token-0>{Token-0}</Token-0>
<RequestId>{RequestId}</RequestId>
<HostId>{HostId}</HostId>
</Error>
问题是 HttpURLConnection
默默地将 Content-Type: application/x-www-form-urlencoded
添加到请求中。这很烦人,因为在 HttpURLConnection
object.
的请求中确定 headers 是什么并不容易
无论如何。这是正确的代码
uri = new URL(oneTimeUploadUrl);
// Setup Connection
HttpsURLConnection http = (HttpsURLConnection) uri.openConnection();
http.setDoOutput(true);
http.setRequestMethod("PUT");
http.setRequestProperty("Content-Type"," "); // remove Content-Type header
// Write Data
OutputStream os = http.getOutputStream();
os.write(_bytes);
os.flush();
os.close(); // request gets sent off to the server
另请参阅:HttpURLConnection PUT to Google Cloud Storage giving error 403
我正在使用 AWS Lambda 为我的移动产品创建一个简单的上传服务。
在服务器上,我使用以下代码
生成预签名URLvar params = {
Bucket: targetS3Bucket,
Key: key,
Body: '',
ContentType: event.contentType,
Expires: 60
};
s3.getSignedUrl('putObject', params, function (err, url){
context.done(null, {
'oneTimeUploadUrl': url,
'resultUrl': urlPrefix + key
});
});
其中 targetS3Bucket
是 S3 上文件夹的路径,key
是文件本身的名称,urlPrefix
是 S3 上文件的 HTTP 位置的根目录(即:s3.amazonaws.com/some-folder/
)
将此代码与内置 HTTP 库一起使用(也就是说,不使用任何 aws SDK)在 PC 和 iOS 上都可以正常工作,但是不在 Android.
最新版本的 Android 客户端代码如下所示:
uri = new URL(oneTimeUploadUrl);
// Setup Connection
HttpsURLConnection http = (HttpsURLConnection) uri.openConnection();
http.setDoOutput(true);
http.setRequestMethod("PUT");
// Write Data
OutputStream os = http.getOutputStream();
os.write(_bytes);
os.flush();
os.close(); // request gets sent off to the server
这一直失败,代码为 400
。我尝试了几种方法,例如更改编码、使用 HttpsURLConnection
的非 https 版本和其他一些方法,但无济于事。
我宁愿避免引入 AWS SDK,因为我只需要这个单一功能即可工作,并且使用这个 lambada 端解决方案可以在除 android.[=20 之外的所有平台上使用=]
这是从 AWS 返回的 XML。返回的消息令人困惑,因为客户端从不更改令牌,并且相同的过程在其他设备上成功。
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidToken</Code>
<Message>The provided token is malformed or otherwise invalid.</Message>
<Token-0>{Token-0}</Token-0>
<RequestId>{RequestId}</RequestId>
<HostId>{HostId}</HostId>
</Error>
问题是 HttpURLConnection
默默地将 Content-Type: application/x-www-form-urlencoded
添加到请求中。这很烦人,因为在 HttpURLConnection
object.
无论如何。这是正确的代码
uri = new URL(oneTimeUploadUrl);
// Setup Connection
HttpsURLConnection http = (HttpsURLConnection) uri.openConnection();
http.setDoOutput(true);
http.setRequestMethod("PUT");
http.setRequestProperty("Content-Type"," "); // remove Content-Type header
// Write Data
OutputStream os = http.getOutputStream();
os.write(_bytes);
os.flush();
os.close(); // request gets sent off to the server
另请参阅:HttpURLConnection PUT to Google Cloud Storage giving error 403