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

从S3桶调用AWS HTTP API Gateway POST接口时出现403 Forbidden错误

解决S3静态页面调用IAM授权的HTTP API Gateway 403错误

根据你的代码和配置,Postman能正常请求但前端页面报403,核心问题在于签名构建时的请求细节与实际发送的请求不匹配,以下是具体问题点和修复方案:

1. HttpRequest 初始化错误

你创建AWS.HttpRequest时未指定请求方法,且可能传入了不完整的endpoint路径,导致签名时使用默认的GET方法,和实际POST请求不匹配,直接触发IAM签名验证失败。

修复:

  • 确保endpoint是完整的HTTPS URL(比如https://xxxx.execute-api.us-east-1.amazonaws.com/prod/remove)
  • 手动设置request的method为POST,并提前写入请求body和正确的Content-Type

2. Content-Type 配置错误

你的代码在循环签名headers时反复设置Content-Type: text/json,存在两个问题:

  • text/json不是标准的JSON内容类型,正确值应为application/json
  • 签名时的request headers中未包含这个Content-Type,导致实际发送的header与签名时的不一致,IAM验证不通过

修复:在构建签名前就把Content-Type添加到request的headers中,确保签名包含该字段。

3. 请求Body未纳入签名计算

POST请求的body是签名计算的一部分,你当前的代码没有把请求body设置到AWS.HttpRequest实例中,导致签名时的payload hash与实际发送的body不匹配,触发403。

修复:将JSON字符串写入request的body属性。

完整修复后的代码

<script>
document.getElementById('dialler').addEventListener('click', async e => {
    console.log('clicked');
    e.preventDefault();

    const formElement = document.querySelector('form');
    const formData = new FormData(formElement);
    const telephoneNumber = formData.get('telephone');
    const jsonBody = { TelephoneNumber: telephoneNumber };
    const jsonBodyStr = JSON.stringify(jsonBody);

    const region = 'XXX';
    // 替换为完整的API Gateway endpoint URL
    const endpoint = 'https://xxxx.execute-api.XXX.amazonaws.com/XXX/remove';
    const accessKeyId = 'XXX';
    const secretAccessKey = 'XXXX';

    AWS.config.update({
        accessKeyId: accessKeyId,
        secretAccessKey: secretAccessKey,
        region: region
    });

    // 初始化HttpRequest,指定完整URL和区域
    const request = new AWS.HttpRequest(endpoint, region);
    // 设置请求方法为POST
    request.method = 'POST';
    // 设置正确的Content-Type
    request.headers['Content-Type'] = 'application/json';
    // 写入请求body,确保签名包含payload
    request.body = jsonBodyStr;
    // 设置host header(签名必需)
    request.headers.Host = new URL(endpoint).hostname;

    // 构建签名
    const signer = new AWS.Signers.V4(request, 'execute-api');
    signer.addAuthorization(AWS.config.credentials, new Date());

    // 准备fetch的headers
    const headers = {};
    for (const [key, value] of Object.entries(request.headers)) {
        headers[key] = value;
    }

    try {
        const response = await fetch(endpoint, {
            method: 'POST',
            headers: headers,
            body: jsonBodyStr
        });

        if (!response.ok) {
            throw new Error(`HTTP Error: ${response.status}`);
        }

        const data = await response.json();
        console.log('API Response:', data);
    } catch (error) {
        console.error('Error calling API:', error);
    }
});
</script>

额外注意事项

  • 硬编码凭证风险:前端代码直接写入AK/SK会导致密钥泄露,建议改用Amazon Cognito身份池为前端用户提供临时凭证,而非长期密钥。
  • CORS配置验证:虽然你的CORS配置看似开放,但如果API Gateway返回的响应headers中有IAM相关的头部(如x-amzn-RequestId),需要在S3的CORS配置中ExposeHeaders里添加这些头部,避免浏览器拦截响应。
  • IAM权限确认:确保你使用的AK/SK对应的IAM用户拥有execute-api:Invoke权限,且资源路径匹配你的API Gateway端点(比如arn:aws:execute-api:{region}:{account-id}:{api-id}/{stage}/POST/remove)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:02:36