如何从与 C# lambda 集成(而非代理集成)的 Amazon API 网关获取正确的 http 状态代码?

2024-06-29

我正在使用 C# lambda 与 API 网关集成。我希望 API 网关返回正确的错误代码,例如 400、404、500 等。

API网关模块tf文件

provider "aws" {
  version = "<= 2.70.0"
  region = "${var.aws_region}"
  profile = "${var.aws_profile}"
}

terraform {
  # The configuration for this backend will be filled in by Terragrunt
  backend "s3" {}
}

data "terraform_remote_state" "api_state" {
  backend = "s3"

  config {
    region = "${var.aws_region}"
    profile = "${var.aws_profile}"
    bucket = "${var.s3_remote_state_bucket_name}"
    key = "${var.s3_remote_state_key_name_api}"
  }
}

data "terraform_remote_state" "resource_state"{
  backend = "s3"
  config {
    region = "${var.aws_region}"
    profile = "${var.aws_profile}"
    bucket = "${var.s3_remote_state_bucket_name}"
    key = "${var.s3_remote_state_key_name_resource}"
  }
}

data "terraform_remote_state" "lambda_alias"{
  backend = "s3"

  config {
    region = "${var.aws_region}"
    profile = "${var.aws_profile}"
    bucket = "${var.s3_remote_state_bucket_name}"
    key = "${var.s3_remote_state_key_name_lambda}"
  }
}

resource "aws_api_gateway_method" "http-method" {
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  http_method = "GET"
  authorization = "CUSTOM"
  authorizer_id = "${data.terraform_remote_state.api_state.Authorizers[var.Authorizer]}"
  request_parameters = "${var.api_request_params_required}"
}

resource "aws_api_gateway_integration" "integration_GET" {
  rest_api_id             = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  resource_id             = "${data.terraform_remote_state.resource_state.api_resource_id}"
  http_method             = "${aws_api_gateway_method.http-method.http_method}"
  integration_http_method = "POST"
  type                    = "AWS"
  uri                     = "arn:aws:apigateway:${var.aws_region}:lambda:path/2015-03-31/functions/${data.terraform_remote_state.lambda_alias.alias_lambda_arn}/invocations"
  passthrough_behavior = "WHEN_NO_TEMPLATES"
  request_templates = {
    "application/json" = "${file("api_gateway_body_mapping.template")}"
  }
}

resource "aws_api_gateway_model" "error_response" {
  rest_api_id  = "${aws_api_gateway_rest_api.api_gateway_rest_api.id}"
  name         = "ErrorResponse"
  description  = "The error respone object for all endpoints"
  content_type = "application/json"

  schema = <<EOF
  {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type" : "object",
    "properties": {
          "body": {
              "type": "string"
          },
          "statusCode" : {
              "type": "number"
          }
      }
  }
EOF
}

resource "aws_api_gateway_method_response" "method_response" {
  depends_on = ["aws_api_gateway_method.http-method"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "200"
}

resource "aws_api_gateway_method_response" "method_bad_request" {
  depends_on = ["aws_api_gateway_method.http-method"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "400"
  response_models {
    "application/json" = "${aws_api_gateway_model.error_response}"
  }
}

resource "aws_api_gateway_method_response" "method_not_found" {
  depends_on = ["aws_api_gateway_method.http-method"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "404"
  response_models {
    "application/json" = "${aws_api_gateway_model.error_response}"
  }
}

resource "aws_api_gateway_method_response" "method_error" {
  depends_on = ["aws_api_gateway_method.http-method"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "500"
  response_models {
    "application/json" = "${aws_api_gateway_model.error_response}"
  }
}

resource "aws_api_gateway_integration_response" "get_integration_response_success" {
  depends_on = ["aws_api_gateway_method_response.method_response", "aws_api_gateway_integration.integration_GET"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "${aws_api_gateway_method_response.method_response.status_code}"
  response_templates {
    "application/json" = ""
  }
}

resource "aws_api_gateway_integration_response" "get_integration_response_error" {
  depends_on = ["aws_api_gateway_method_response.method_error", "aws_api_gateway_integration.integration_GET"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "${aws_api_gateway_method_response.method_error.status_code}"
  selection_pattern = ".*statusCode['\"]\\s*:\\s*['\"]?500.*"
  response_templates {
    "application/json"="${file("api_gateway_exception_mapping.template")}"
  }
}

resource "aws_api_gateway_integration_response" "get_integration_response_bad_request" {
  depends_on = ["aws_api_gateway_method_response.method_bad_request", "aws_api_gateway_integration.integration_GET"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "${aws_api_gateway_method_response.method_bad_request.status_code}"
  selection_pattern = ".*statusCode['\"]\\s*:\\s*['\"]?400.*"
  response_templates {
    "application/json"="${file("api_gateway_exception_mapping.template")}"
  }
}

resource "aws_api_gateway_integration_response" "get_integration_response_not_found" {
  depends_on = ["aws_api_gateway_method_response.method_not_found", "aws_api_gateway_integration.integration_GET"]
  http_method = "${aws_api_gateway_method.http-method.http_method}"
  resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
  rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
  status_code = "${aws_api_gateway_method_response.method_not_found.status_code}"
  selection_pattern = ".*statusCode['\"]\\s*:\\s*['\"]?404.*"
  response_templates {
    "application/json"="{}"
  }
}

api_gateway_exception_mapping.template:

#set($inputRoot = $util.parseJson($input.path('$.errorMessage')))
{
"Error":"$inputRoot.body"
}

集成响应映射如下快照所示

我们在 python 中创建了带有 lambda 集成的 API,我抛出了一个自定义 APIException,如下所示,它起作用了。

class ApiException(Exception):
    """Our custom APIException class which derives from the built-in Exception class"""

    def __init__(self, status_code, message: str, **kwargs):
        self.status_code = status_code
        self.message = message
        kwargs["statusCode"] = status_code
        kwargs["body"] = message
        super().__init__(json.dumps(kwargs))

在 lambda 处理程序内部:

from .utils import ApiException
def lambda_handler(event, context):
    try:
        """
        CODE FOR LAMBDA HANDLER
        """
    except Exception:
        ex = ApiException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
                           message='Internal Error')
        print("exception string: %s", ex)
        raise ApiException(
            status_code=500,
            message='Internal server error')

当我记录异常时,我得到以下输出

{
    "statusCode": 500,
    "body": "Internal Server Error"
}

我还提到了这个 stackoverflowanswer https://stackoverflow.com/questions/31329495/is-there-a-way-to-change-the-http-status-codes-returned-by-amazon-api-gateway关于如何在 API Gateway 响应中获取正确的错误代码。我修改了一点以引发异常,而不是仅仅返回一个 jsonstatusCode, 回复body and headers因为我没有使用 AWS_PROXY 集成类型

APIException.cs

public class APIException : Exception
{
    public int statusCode;
    public string body;
    public APIException() : base() {}
    public APIException(int statusCode, string message): base(message) {
        this.statusCode = statusCode;
        JObject json = JObject.Parse(message);
        this.body = json["body"].ToString();
    }
}

拉姆达处理程序:

namespace LambdaFunction
{
    public class Function
    {
        public async Task<JObject> FunctionHandler(JObject events, ILambdaContext context)
        {
           try
            {
                ValidateQueryParams(events, context);
                JObject response = JObject.Parse(@"{
                    'mesage': 'success',
                }");

                return response;
            }
            catch(HttpListenerException ex)
            {
                string err = (new JObject(
                    new JProperty("statusCode", ex.ErrorCode),
                    new JProperty("body", ex.Message)
                )).ToString();
                return new APIException(ex.ErrorCode, err);
            }
            catch(Exception ex)
            {
                int err_code = (int)HttpStatusCode.InternalServerError
                string err = (new JObject(
                    new JProperty("statusCode", err_code),
                    new JProperty("body", "Internal Server Error")
                )).ToString();
                var err_ex = new APIException(err_code, err);
                context.Logger.LogLine("Unhandled exception occurred: " + ex.ToString());
                return err_ex;
            }
        }
    }
}

在抛出异常之前我已经记录了异常,看看我们得到了什么,这就是我得到的

{
    "statusCode": 500,
    "body": "Internal Server Error",
    "StackTrace": null,
    "Message": "{\n  \"statusCode\": 500,\n  \"body\": \"Internal Server Error\"\n}",
    "Data": {},
    "InnerException": null,
    "HelpLink": null,
    "Source": null,
    "HResult": -2146233088
}

但使用上面的代码,我仍然只是得到响应代码为 200 且响应正文如下

{
    "errorType": "APIException",
    "errorMessage": "{\n  \"statusCode\": 500,\n  \"body\": \"Internal Server Error\"\n}",
    "stackTrace": [
        "..."
    ]
}

我不确定我哪里出错了。任何帮助将不胜感激。谢谢。


我已经弄清楚了这个问题。 CS.ToString()转换的函数JObject进入字符串是格式化字符串并添加新行字符\n默认情况下。但API网关中用于识别错误代码的正则表达式不考虑换行符。修复方法非常简单。我们需要告诉.ToString()函数不应该进行任何格式化。所以,而不是

new JObject(
    new JProperty("statusCode", err_code),
    new JProperty("body", "Internal Server Error")
)).ToString();

你需要做

new JObject(
    new JProperty("statusCode", err_code),
    new JProperty("body", "Internal Server Error")
)).ToString(Formatting.None);

它起作用了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从与 C# lambda 集成(而非代理集成)的 Amazon API 网关获取正确的 http 状态代码? 的相关文章

  • static const 和 constexpr 变量有什么区别? [复制]

    这个问题在这里已经有答案了 我明白 一个constexpr variable可以在编译时使用 对于模板 或者例如 static assert 但如果我想在没有 constexpr 的情况下做到这一点 我可以static const 自从 C
  • C# 参数隐式转换

    有这个代码 class Program static void Main string args Check 3 Console ReadLine static void Check int i Console WriteLine I am
  • 有关堆栈大小的警告消息

    I use Visual Studio 2010 with Code Analysis活性 在我的代码中 有一行在函数中分配一些内存 TCHAR someString 40000 代码分析抛出警告信息 警告 C6262 函数使用 40000
  • 如何获取picturebox非公开成员的值?

    我需要从 picturebox 的非公共成员获取图像矩形的值 如何获得该值 提前致谢 这是使用反射获取值的方法 PropertyInfo pInfo pictureBox1 GetType GetProperty ImageRectangl
  • 异步方法调用和模拟

    为什么模拟用户上下文仅在异步方法调用之前可用 我编写了一些代码 实际上基于 Web API 来检查模拟用户上下文的行为 async Task
  • x64 DLL 导出函数名称

    我正在尝试将 32 位 dll 和应用程序 移植到 64 位 并且我成功地构建了它而没有错误 当尝试使用我的 64 位应用程序加载它时 我注意到导出的函数名称不同 这就是我导出函数的方式 ifdef cplusplus extern C e
  • 如何在Linux上正确设置串行通信

    我正在尝试从 FPGA 板读取数据以及向 FPGA 板写入数据 该板本身附带一个驱动程序 每当板插入时 该驱动程序都会创建一个名为 ttyUSB0 的终端设备 在 FPGA 上 实现了异步接收器和发送器 并且它们似乎可以工作 然而 C 方面
  • 动态方法的实际例子?

    我想学习动态方法及其使用 C 的实际示例 动态方法和Reflection有什么关系吗 请帮我 我们正在使用动态方法来加速反射 这是我们的反射优化器的代码 只比直接调用慢10 比反射调用快2000倍 public class Reflecti
  • 在所有 DataTable 列中查找字符串

    我正在尝试找到一种快速方法来在所有数据表列中查找字符串 跟随不起作用 因为我想在所有列值中搜索 string str whatever foreach DataRow row in dataTable Rows foreach DataCo
  • Elastic Beanstalk 未创建 ssl.conf

    我正在关注these https docs aws amazon com elasticbeanstalk latest dg https singleinstance php html有关在 Elastic Beanstalk 管理的 E
  • 错误:非聚合类型“vector”无法使用初始值设定项列表进行初始化

    我是 C 的初学者 每次跑步时vector
  • 无法从 GetSystemTime() 获取毫秒

    我正在尝试打印秒和毫秒分辨率计时 我正在使用GetSystemTime 这是我的代码 GetSystemTime datetime RETAILMSG 1 T Time After Data Sent to USB d d r n date
  • 在 C# 中获取 Selenium RemoteWebDriver 的会话 ID

    我正在尝试获取在 SauceLabs 云上运行的测试的会话 ID 但我似乎无法访问它 我尝试过以下方法 Returns null var sessionId string RemoteWebDriver driver Capabilitie
  • 同一个盒子上的进程间通信 - 2 个应用程序或进程之间的通信

    在同一机器上的应用程序之间实现进程间通信的最佳方法是什么 两者都是用 C 编写的 管理器应用程序将向其他应用程序发送命令 例如 停止 启动 它还将监视应用程序并可能要求提供数据 所有应用程序都将在同一台运行 Windows 7 操作系统的计
  • C#:迭代数据表:Rows、Select() 或 AsEnumerable()

    foreach DataRow row in myDataTable Select foreach DataRow row in myDataTable AsEnumerable foreach DataRow row in myDataT
  • Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential 不采用 2 个参数?

    我在代码中使用 ADAL 我想要使 用的一件事是使用不同的凭据 因此我可以在控制台程序中针对 Azure AD 授权不同的用户 Microsoft IdentityModel Clients ActiveDirectory UserCred
  • 画笔和钢笔使用指南

    制作 GDI 画笔和钢笔有多贵 我应该在添加所需的基础上创建它们并将它们包装在 using 中以便快速处理它们 还是应该创建一个类似于 System Drawing Brushes 类的静态类 IMO 它们足够高效 您通常不应该创建在多个方
  • 选择数据结构

    根据需求使用不同的数据结构 但我如何知道应该使用哪种数据结构 我只是想知道如何选择合适的数据结构 谢谢 此流程图适用于 C 中的 STL 但您可以用 C 实现 STL 容器支持的任何数据结构 列表是一个链接列表 Vector是一个动态数组
  • C# 如何更改 windows.forms.listview 中的网格线颜色

    如何更改 windows forms listview 中的网格线颜色 我认为没有办法在不覆盖 Paint Event 的情况下在列表视图上执行此操作 但是 如果您能够切换到网格视图 您可以这样做 this dataGridView1 Gr
  • 配置 SourceTrail 以接受带有 @ 语法的嵌入式 c/c++ 头文件

    我正在尝试使用 Sourcetrail https www sourcetrail com https www sourcetrail com 快速了解 pic18 系列微控制器的一些旧嵌入式 c c 源代码 导入硬件包含文件时出现错误 该

随机推荐

  • 错误:未找到 Flutter SDK。在 local.properties 文件中使用 flutter.sdk 定义位置

    ERROR Flutter SDK not found Define location with flutter sdk in the local properties file 我已经导入了 Flutter 示例应用程序mahtab al
  • 使用实体框架实现 if-not-exists-insert,无需竞争条件

    使用 LINQ to Entities 4 0 是否有正确的模式或构造来安全地实现 如果不存在则插入 例如 我目前有一个跟踪 用户收藏夹 的表 用户可以在其收藏夹列表中添加或删除文章 基础表不是真正的多对多关系 而是跟踪一些附加信息 例如添
  • 如何使用 jQuery 解析 JavaScript 对象

    jQuery JavaScript 中用于解析 JSON 对象并返回键 值对的 foreach 等效项是什么 JSON 对象 是什么意思 JSON 是一种用于序列化对象的文本格式 如果要循环访问通过反序列化 JSON 字符串获得的对象中的属
  • Maya python 连接选择的属性

    我一直在尝试制作一个简单的脚本 它将采用两个视口选择 然后基本上将第二个视口的旋转连接到第一个 我不确定如何正确地从视口选择中为对象创建变量 这是我的尝试 但不起作用 import maya cmds as cmds sel cmds ls
  • 从不同的线程访问对象

    我有一个服务器类 它基本上等待来自客户端的连接 在该类中 我创建了一个 NetworkStream 对象 以便能够从客户端接收字节 由于 NetworkStream Read 方法不是异步的 这意味着它将等到从客户端读取字节才能继续执行类似
  • Python - 将列表作为参数传递给 SQL,以及更多变量

    我试图在 python 3 6 中将未知数量的参数传递给 SQL Server 这是我使用 pypyodbc 的代码 cursor cnxn cursor theargs 1033286869 1053474957 1063654630 1
  • allure2 侦听器在控制台中输出步骤

    我正在使用 Allure2 和 TestNG 我想编写自己的侦听器 在控制台输出中打印 Steps 我在 allure 中看到了 StepLifecycleListener 接口 但我无法在 TestNg 中实现此侦听器 有什么指点吗 Ov
  • Firebase 存储图像缓存不起作用

    有两个图像 uri 第一个位于火力基地存储第二个是示例图像反应原生博客 我相信 recat native 的Image组件是可缓存的
  • 如何在网页上显示进度条直到网页完全加载?

    我想在网页中显示进度条 加载弹出窗口 直到页面完全加载 我的网页很重 因为它包含一个 HTML 编辑器 这是一个基于 jQuery 的 HTML 编辑器 需要很多时间才能完全加载 在加载时 我希望在页面上显示一个进度条 该进度条将在整个页面
  • 如何在 Cocoa 中将 NSString 转换为 unsigned int?

    我的申请收到了NSString含有一个unsigned int NSString 没有 myString unsignedIntegerValue 方法 我希望能够从字符串中取出值而不破坏它 然后将其放入NSNumber 我正在尝试这样做
  • Android SQLite插入语句错误

    在我的数据库中 我修改了我的表 以前它有 2 列 不包括 id 现在它有 3 列 不包括 id 因此 每当我添加元组时 它都会显示错误 为了添加元组 我调用了 addContact 函数 private static final int D
  • AWS Step Function 中的 lambda 能否知道启动它的步骤函数的“执行名称”?

    我有这个步骤函数 有时可能会失败 我想将其记录在 发电机 数据库中 方便的是 如果我可以创建一个新的错误处理步骤 而那个人只需从某个地方获取 执行名称 在上下文中没有找到它 并将其记录为失败 那可能吗 AWS Step Functions
  • 拆分 Apache Camel 后恢复标头值

    我有一个 xml 其中使用 split 标签在 Spring DSL 中进行处理 我所做的基本上是在 xml 中搜索一个值 当我找到这个值时 我需要获取另一个标签的值 同一元素的子元素 并将其保存到标头 这个操作看起来很简单 但我无法在拆分
  • Android:Html 锚链接仅在 Web 视图中有效一次

    在使用锚链接加载 html 内容时 我在 webview 中遇到一些奇怪的问题 以下代码非常适合锚标记 但是只有一次 第二次当我按下锚标签时不工作 protected void onCreate Bundle savedInstanceSt
  • 通用存储库与 EF 4.1 的意义何在

    当我深入研究 DbContext DbSet 和相关接口时 我想知道为什么您需要围绕这些实现实现一个单独的 通用 存储库 看起来 DbContext 和 IDbSet 可以完成您需要的一切 并在 DbContext 中包含 工作单元 我是否
  • 如何将国家/地区代码与电话号码分开?

    我的数据库中有很多电话号码 例如 1 123 456 7890 我要做的是将国家 地区拨号代码 在本例中为美国 加拿大的 1 与电话号码分开 我尝试创建所有国家 地区的 JSON 列表 并在加载页面时将电话号码和国家 地区代码分开 它工作正
  • 在 Python 中为非唯一列表创建虚拟列

    目前我有下一个数据框 import pandas as pd df pd DataFrame ID 1 2 3 4 5 col2 a b c c d e f f b f a c b b a b print df ID c
  • 在 Ubuntu 上的 Tomcat 中加载共享本机库

    如何在 Ubuntu 上的 Tomcat6 中加载共享库 我创建了一个名为 libawragrids so 的库 awragrids 并将其放置在 var lib tomcat6 shared 我在调用启动 tomcat 的终端中设置了以下
  • ASP.NET MVC3 Ajax.ActionLink - 条件确认对话框

    我有一个 Ajax ActionLink 仅当满足某些条件 用户有未保存的更改 时 我才希望显示一个确认对话框 我创建了一个 JavaScript 函数 它根据需要显示确认对话框 并根据响应返回 true 或 false 我将其绑定到 Ac
  • 如何从与 C# lambda 集成(而非代理集成)的 Amazon API 网关获取正确的 http 状态代码?

    我正在使用 C lambda 与 API 网关集成 我希望 API 网关返回正确的错误代码 例如 400 404 500 等 API网关模块tf文件 provider aws version lt 2 70 0 region var aws