通过 API Gateway 从 s3 静态网站获取到 Lambda 函数,给出 415 Unsupported Media Type 错误

Posted

技术标签:

【中文标题】通过 API Gateway 从 s3 静态网站获取到 Lambda 函数,给出 415 Unsupported Media Type 错误【英文标题】:Fetch from s3 static website to Lambda function, through API Gateway, gives 415 Unsupported Media Type error 【发布时间】:2021-08-02 15:25:27 【问题描述】:

我正在尝试通过 API Gateway 从我的 s3 托管静态网站获取(方法 POST)到我的 lambda 函数之一,运行时语言是 nodejs。

遵循关于 html post 表单的 sn-ps、执行 post 请求并将表单数据转换为 json 的 JS 脚本,以及我的 nodejs lambda 函数。

<form name='form' id="myForm">
            <div id=whatpageisit><a href='index.html'>LOGIN</a>SIGNUP  </div>
            
            <p> <label>Username <input type='text' name='username' value=''></label> </p>
            <p> <label>Email <input type='email' name='email' value=''></label> </p>
            <p> <label>Password <input type='password' name='password' value=''></label> </p>
            <p> <label>Conferma Password <input type='password' name='conferma_password' value=''></label> </p>
            
            <p> <div id="submit"><label>&nbsp;<input type='submit'></label></div> </p>
        </form>

---------- JS

<script> // https://gomakethings.com/serializing-form-data-with-the-vanilla-js-formdata-object/
            document.addEventListener('submit', function (event) 
                event.preventDefault(); 
                
                fetch('', 
                    //mode:"no-cors",
                    method: 'POST',
                    body: JSON.stringify(Object.fromEntries(new FormData(event.target))),
                    headers: 
                        'Content-type': 'application/json; charset=UTF-8'
                    
                ).then(function (response) 
                if (response.ok) 
                    return response.json();
                
                return Promise.reject(response);
                ).then(function (data) 
                    console.log(data);
                ).catch(function (error) 
                    console.warn(error);
                );
            );
        </script>

--- 拉姆达函数

    exports.handler =  (event, context, callback) =>  
  context.callbackWaitsForEmptyEventLoop = false; 
      pool.getConnection(function(err,connection)
        var user = event.body.username;
        var email = event.body.email;
        var password = event.body.password;
        var sql0 = "INSERT INTO users VALUES ('"+user+"','"+email+"','"+password+"','')";
     
        connection.query(sql0, function (error, result, fields) 
          connection.release();
          if (error) 
            callback(error); 
           else   callback(null,result); 
         
        ); //end connection.query
      
      ); //end pool.getConnection

我还想澄清一下,我相信我的函数具有所有正确的权限(在与 Lambda 函数关联的 IAM 角色中),就好像我测试网关以 json 格式插入请求正文一样,查询已成功插入D B。 这里有一个响应屏幕,以及响应标题:

指定我在我的 API 上启用了 CORS,并且我的标头响应包含 AllowControlallowOrigin : *.

尽管,当我尝试通过我的主页运行我的请求时,我得到了这个错误

如果我尝试在 JS 中插入模式:no-cors,我会收到此错误: POST net::ERR_ABORTED 415(不支持的媒体类型。

所以我找到了一些线程,其中解释了 mode: no-cors 我的表单数据在 text/char 中,而不是网关期望的 application/json 中。 (网关有关于内容类型application/json的集成请求(Lambda类型)的映射模板)

我尝试将映射模板正文内容类型更改为 text/char,并从 ---> 变为:

现在,正如我们的第一个错误所预期和预期的那样,启用模式:no-cors 将导致不透明的响应:

所以我不知道该怎么做以及是什么导致了我的问题。首先,我不明白为什么当我从网关启用 CORS 时它会提示我有关 CORS 的错误,甚至响应标头包含 AllowControlAllowOrigin :*。

我还尝试在 s3 存储桶选项错误页面中添加 index.html,正如有人建议的那样作为不透明响应的解决方案,但我得到

【问题讨论】:

415错误是根本问题; CORS 消息是一个副作用。 那么问题是我如何传递表单数据,那么JS脚本呢? 我的猜测是,您使用的某种 API 的数据编码方式与 JSON 不同?如果是这种情况,那么你需要这个:docs.aws.amazon.com/apigateway/latest/developerguide/…. @MarkoE 我怎么知道它需要什么样的编码?如果我通过这种 json 请求测试我的网关 "username": "mike", "email": "mike@gmail.com", "password": "grvdsc" ,我得到 "errorMessage": "Cannot read属性 'username' of undefined",对于 HTTP 获取。昨天至少在 Gateway 上运行良好。 编码取决于您将数据传递到的后端。因此,基本上有四种类型的后端集成,如果后端可以处理 JSON 数据,则其中两种被认为是“代理”。其他两个要求您使用 VTL 重写数据(在我之前评论的链接中)。解释如下:docs.aws.amazon.com/apigateway/latest/developerguide/…. 【参考方案1】:

最后我需要做的就是:将 Origin 添加到 API -> Enable Cors -> Allow Control Allow headers。

【讨论】:

以上是关于通过 API Gateway 从 s3 静态网站获取到 Lambda 函数,给出 415 Unsupported Media Type 错误的主要内容,如果未能解决你的问题,请参考以下文章

AWS S3 静态站点 CORS jquery ajax POST 到 API Gateway

AWS CDK 将 API Gateway URL 传递到同一堆栈中的静态站点

使用 Learner Lab - 使用 S3 静态网页上传图片,搭配 API Gateway 与 Lambda

如何将 AWS CloudFront 和 API Gateway 并排用于同一个域?

如何通过节点 expressjs 从 s3 提供静态网站?

通过 ElasticBeansStalk 上托管的 API Gateway 在 AWS S3 上上传图像