You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端结合Cognito的Amazon S3预签名URL报错400优化咨询

问题根因

你遇到的预签名URL提前过期触发400错误,核心原因是Cognito返回的临时凭证有效期短于你设置的预签名URL有效期:
Cognito身份池默认给未认证用户发放的临时凭证有效期仅为1小时,就算你给预签名URL设置了12小时过期,用来生成签名的临时凭证先过期后,URL自然会提前失效,返回400错误。

改进推荐

  • 对齐有效期配置
    预签名URL的有效期不能超过生成它所用的凭证的有效期:
    1. 可以直接把预签名URL的过期时间改为小于3600秒(1小时),比如设置System.currentTimeMillis() + 3500000,留一定缓冲时间
    2. 如果确实需要更长有效期的URL,登录AWS控制台进入对应Cognito身份池,在「身份验证提供者」-「未验证」选项下,把凭证有效期调整到最长12小时,再对应设置预签名URL的有效期不超过该值
  • 调整预签名URL生成时机
    不要在onCreate阶段一次性生成URL长期持有,改成每次需要请求S3资源前再当场生成预签名URL,避免APP退后台长时间挂起后复用过期URL
  • 新增错误重试逻辑
    给Volley请求添加错误拦截逻辑,捕获到400错误后,先销毁旧的S3客户端实例,重新生成Cognito凭证、新的预签名URL后再重试请求
  • 修复主线程阻塞问题
    你当前在onCreate中调用thread.join()会阻塞主线程,极易触发ANR,改为异步回调的方式获取预签名URL后再发起网络请求

改进代码示例

调整后的RunnableAWSS3.java

public class RunnableAWSS3 implements Runnable {
    private final Context context;
    private final OnURLGeneratedListener listener;

    public interface OnURLGeneratedListener {
        void onSuccess(String presignedUrl);
        void onError(Exception e);
    }

    public RunnableAWSS3(@NonNull Context context, OnURLGeneratedListener listener) {
        this.context = context.getApplicationContext();
        this.listener = listener;
    }

    @Override
    public void run() {
        try {
            CognitoCachingCredentialsProvider cognitoProvider = new CognitoCachingCredentialsProvider(
                    context,
                    "us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx",
                    Regions.US_EAST_1
            );
            // 每次生成URL前清空旧的缓存凭证,强制拿最新有效凭证
            cognitoProvider.clearCredentials();
            AmazonS3 amazonS3 = new AmazonS3Client(cognitoProvider, Region.getRegion(Regions.US_EAST_1));
            // 有效期设置为59分钟,小于默认1小时的凭证有效期
            URL presignedURL = amazonS3.generatePresignedUrl(
                    "xxxxxxxxxxxxxxxxxxxxxxxx",
                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                    new Date(System.currentTimeMillis() + 3540000)
            );
            listener.onSuccess(presignedURL.toString());
        } catch (Exception e) {
            listener.onError(e);
        }
    }
}

调整后的MainActivity.java调用逻辑

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 异步获取预签名URL后再发起请求,不阻塞主线程
    new Thread(new RunnableAWSS3(this, new RunnableAWSS3.OnURLGeneratedListener() {
        @Override
        public void onSuccess(String presignedUrl) {
            JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, presignedUrl, null, response -> {
                // 处理返回结果
            }, error -> {
                // 400错误时重新生成URL重试
                if (error.networkResponse != null && error.networkResponse.statusCode == 400) {
                    new Thread(new RunnableAWSS3(MainActivity.this, this)).start();
                }
            });
            // 把请求加入Volley队列
            Volley.newRequestQueue(MainActivity.this).add(jsonObjectRequest);
        }

        @Override
        public void onError(Exception e) {
            // 处理初始化错误
        }
    })).start();
}

内容的提问来源于stack exchange,提问作者Miha M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 02:15:06