在 Angular 11 中,如何通过 API Gateway 将应用程序/json HTTP POST 到 AWS Lambda?

Posted

技术标签:

【中文标题】在 Angular 11 中,如何通过 API Gateway 将应用程序/json HTTP POST 到 AWS Lambda?【英文标题】:In Angular 11, how to HTTP POST application/json to AWS Lambda via API Gateway? 【发布时间】:2021-07-30 16:55:00 【问题描述】:

我计划在 AWS Amplify 中托管一个 Angular 应用程序。它为其 REST API 调用 Lambda 函数。我有一个大部分成功的测试应用程序,但它不能做这件事:将 JSON 数据发布到托管 URI。

在浏览器中,我有一个 Angular 客户端,它有一个按钮,单击时会调用 HttpClient.postHttpClient.request。我有多个我测试过的后端服务器:(1) NestJs/Express,(2) sam local start-api 和 (3) AWS 托管。本地sam 服务器和托管环境同步并使用相同的template.yaml。所有三台服务器都接受Content-Type 中的application/jsonapplication/x-www-form-urlencoded

Content-Type、服务器实例和 HttpClient 方法(postrequest(“POST”,...))的每个组合都可以在托管的 lambda 函数中使用 Json。它似乎立即被拒绝了。

该调用从未进入 Cloudwatch 日志,我猜这意味着它的格式不正确并被我不知道是什么过滤掉了。我对 AWS 很陌生,不熟悉它的特殊性,所以我不确定我可以在托管环境中打开哪些日志记录来捕获它。它失败得如此之快,从来没有到达日志,更不用说我的代码了,我很好奇它有什么问题。

Curl with Json 也可以:curl -X POST -H "Content-Type:application/json" ...

总之,当使用.post().request() 方法将Json 或Form 样式发布到非AWS 和本地AWS Web 服务器时,一切都很好。表单样式 POST 到 AWS 托管(通过 API 网关)也可以工作。使用 Json 手工制作的命令行 POST 也适用于托管的 AWS(通过 API 网关)。

只有从 Angular 托管的 POST 到 AWS 不起作用。

ETA 这是一个代码 sn-p:

const URI_LOCAL = “/api/music”;
const URI_HOSTED = “https://…amazonaws.com/Prod/api/music”;
const headers_j = new HttpHeaders( 'Content-Type': 'application/json' );
const album = "title":"Mullet Beginnings","band":"The Wallabys”;
const body_j = JSON.stringify(album);

// This fails
let res_j$ = this.http.post<any>(URI_HOSTED, body_j,  headers: headers_j );

// This works
const headers_x = new HttpHeaders( 'Content-Type': 'application/x-www-form-urlencoded' );
const body_x = 'title=Dancing Beers&band=Evils Ypsley’;
let res_x$ = this.http.post<any>(URI_HOSTED, body_x,  headers: headers_x );

我也尝试过传递 album 而不是 body_j。两个选项(对象或 JSON 字符串)都适用于 URI_LOCAL。对 URI_HOSTED 都不起作用。

某个地方的某个人必须成功地将 Json 从 Angular 发布到 AWS 托管环境。关于我做错了什么的任何提示?

[ETA] 这是来自浏览器控制台的错误日志:

[Error] Preflight response is not successful
[Error] XMLHttpRequest cannot load https://_SNIP_.amazonaws.com/Prod/api/rebuild due to access control checks.
[Log] POST: (main.js, line 194)
 HttpErrorResponse
  error: XMLHttpRequestProgressEvent isTrusted: true, position: 0, totalSize: 0, lengthComputable: false, loaded: 0, …
  headers: HttpHeaders normalizedNames: Map, lazyUpdate: null, headers: Map
  message: "Http failure response for https://_SNIP_.amazonaws.com/Prod/api/rebuild: 0 Unknown Error"
  name: "HttpErrorResponse"
  ok: false
  status: 0
  statusText: "Unknown Error"
  url: "https://_SNIP_.amazonaws.com/Prod/api/rebuild"
[Error] Failed to load resource: Preflight response is not successful (rebuild, line 0)
client content-type server Result
HttpClient.post json aws hosted Failure
HttpClient.request json aws hosted Failure
curl json aws hosted Success
HttpClient.post json sam local Success
HttpClient.post json nestjs Success
HttpClient.post x-www-form aws hosted Success
HttpClient.post x-www-form sam local Success
HttpClient.post x-www-form nestjs Success

【问题讨论】:

【参考方案1】:

听起来像CORS 问题。

您不仅需要在 API Gateway 中启用 CORS,而且您的 Lambda API Gateway 响应还必须包含访问控制标头。

您的回复应如下所示:

response = 
        statusCode: 204,
        headers: 
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "https://www.example.com",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
        ,
    ;
    return response;
;

【讨论】:

谢谢。这正是它。我稍微编辑了您的示例以匹配我使用的内容。 太棒了。不久前,这让我头疼了好几个小时。 24 小时把我的头撞到墙上。所以,是的,我就在你身边。如此神奇的魔力让一切都可以端到端地工作。我想我永远不会忘记 CORS,现在。我认为它仅用于客户端跨站点脚本,而不是询问服务器的功能。 我知道 CORS,但我不知道我必须在回复中返回标题。很高兴它得到了解决。

以上是关于在 Angular 11 中,如何通过 API Gateway 将应用程序/json HTTP POST 到 AWS Lambda?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Angular 在 mat-h​​eader-cell 行中呈现动态数据

如何通过 API App 公开 Azure APIM API?

如何在 Angular 应用程序中处理 API 凭据?

Angular:如何通过 API 调用使用 JWT 身份验证

使用 Angular 验证用户 API

如何从第三方 api 函数调用/访问 Angular 方法? (将 ApplePay 集成到 Angular 网站中)