首页 文章

有没有办法更改Amazon API Gateway返回的http状态代码?

提问于
浏览
71

例如,如果我想为无效参数返回特定的400错误,或者当lambda函数调用导致创建时返回201 .

我想有不同的http状态代码,但看起来api网关总是返回200状态代码,即使lambda函数返回错误 .

9 回答

  • 56

    对于那些试图解决这个问题并且无法完成这项工作的人(像我一样),请查看此帖子上的devkit评论(保存我的一天):

    https://forums.aws.amazon.com/thread.jspa?threadID=192918

    完全重现它:

    我自己也有这个问题,我相信换行符是罪魁祸首 . foo . 将匹配“foo”的出现,后跟任何字符,除了换行符 . 通常,这可以通过添加'/ s'标志来解决,即“foo . * / s”,但Lambda错误正则表达式似乎并不尊重这一点 . 作为替代方案,您可以使用以下内容:foo( . | \ n)

  • 7

    最简单的方法是use LAMBDA_PROXY integration . 使用此方法,您无需将任何特殊转换设置到API网关管道中 .

    您的返回对象必须类似于下面的代码段:

    module.exports.lambdaHandler = (event, context, done) => {
        // ...
        let response = {
            statusCode: 200, // or any other HTTP code
            headers: {       // optional
                 "any-http-header" : "my custom header value"
            },
            body: JSON.stringify(payload) // data returned by the API Gateway endpoint
        };
        done(null, response); // always return as a success
    };
    

    它确实有一些缺点:必须特别注意错误处理,并将lambda函数耦合到API Gateway endpoints ;那说,如果你真的不打算在其他地方使用它,那就不是什么大问题了 .

  • 6

    1) 通过选中API网关资源定义的"Integration Request"屏幕上标有 "Use Lambda Proxy integration" 的复选框,将API网关资源配置为使用Lambda Proxy Integration . (或者在你的cloudformation / terraform / serverless / etc配置中定义它)

    2) 以两种方式更改lambda代码

    • 适当处理传入的 event (第一个函数参数) . 它不再仅仅是裸负载,它代表整个HTTP请求,包括标头,查询字符串和正文 . 以下示例 . 关键是JSON主体将是需要显式 JSON.parse(event.body) 调用的字符串(不要忘记 try/catch ) . 示例如下 .

    • 通过使用null调用回调来响应,然后是提供HTTP详细信息的响应对象,包括 statusCodebodyheaders .

    • body 应该是一个字符串,所以根据需要做 JSON.stringify(payload)

    • statusCode 可以是一个数字

    • headers 是 Headers 名称对象的对象

    代理集成的示例Lambda事件参数

    {
        "resource": "/example-path",
        "path": "/example-path",
        "httpMethod": "POST",
        "headers": {
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate",
            "CloudFront-Forwarded-Proto": "https",
            "CloudFront-Is-Desktop-Viewer": "true",
            "CloudFront-Is-Mobile-Viewer": "false",
            "CloudFront-Is-SmartTV-Viewer": "false",
            "CloudFront-Is-Tablet-Viewer": "false",
            "CloudFront-Viewer-Country": "US",
            "Content-Type": "application/json",
            "Host": "exampleapiid.execute-api.us-west-2.amazonaws.com",
            "User-Agent": "insomnia/4.0.12",
            "Via": "1.1 9438b4fa578cbce283b48cf092373802.cloudfront.net (CloudFront)",
            "X-Amz-Cf-Id": "oCflC0BzaPQpTF9qVddpN_-v0X57Dnu6oXTbzObgV-uU-PKP5egkFQ==",
            "X-Forwarded-For": "73.217.16.234, 216.137.42.129",
            "X-Forwarded-Port": "443",
            "X-Forwarded-Proto": "https"
        },
        "queryStringParameters": {
            "bar": "BarValue",
            "foo": "FooValue"
        },
        "pathParameters": null,
        "stageVariables": null,
        "requestContext": {
            "accountId": "666",
            "resourceId": "xyz",
            "stage": "dev",
            "requestId": "5944789f-ce00-11e6-b2a2-dfdbdba4a4ee",
            "identity": {
                "cognitoIdentityPoolId": null,
                "accountId": null,
                "cognitoIdentityId": null,
                "caller": null,
                "apiKey": null,
                "sourceIp": "73.217.16.234",
                "accessKey": null,
                "cognitoAuthenticationType": null,
                "cognitoAuthenticationProvider": null,
                "userArn": null,
                "userAgent": "insomnia/4.0.12",
                "user": null
            },
            "resourcePath": "/example-path",
            "httpMethod": "POST",
            "apiId": "exampleapiid"
        },
        "body": "{\n  \"foo\": \"FOO\",\n  \"bar\": \"BAR\",\n  \"baz\": \"BAZ\"\n}\n",
        "isBase64Encoded": false
    }
    

    示例回调响应形状

    callback(null, {
      statusCode: 409,
      body: JSON.stringify(bodyObject),
      headers: {
        'Content-Type': 'application/json'
      }
    })
    

    Notes - 我相信 context 上的方法,例如 context.succeed() 已被弃用 . 它们不再记录,尽管它们似乎仍然有效 . 我认为编写回调API是正确的事情 .

  • 5

    为了能够将自定义错误对象作为JSON返回,您必须跳过几个环节 .

    首先,您必须使Lambda失败并将其传递给字符串化的JSON对象:

    exports.handler = function(event, context) {
        var response = {
            status: 400,
            errors: [
                {
                  code:   "123",
                  source: "/data/attributes/first-name",
                  message:  "Value is too short",
                  detail: "First name must contain at least three characters."
                },
                {
                  code:   "225",
                  source: "/data/attributes/password",
                  message: "Passwords must contain a letter, number, and punctuation character.",
                  detail: "The password provided is missing a punctuation character."
                },
                {
                  code:   "226",
                  source: "/data/attributes/password",
                  message: "Password and password confirmation do not match."
                }
            ]
        }
    
        context.fail(JSON.stringify(response));
    };
    

    接下来,为要返回的每个状态代码设置正则表达式映射 . 使用我在上面定义的对象,您将为400设置此正则表达式:

    ."status":400.

    最后,设置映射模板以从Lambda返回的errorMessage属性中提取JSON响应 . 映射模板如下所示:

    $input.path('$.errorMessage')

    我写了一篇关于此的文章,详细介绍了Lambda到API Gateway的响应流程:http://kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object-and-status-code-from-api-gateway-with-lambda/

  • 16

    我想要Lambda的一个错误是500正确的错误,经过大量的研究后,想出了下面的内容,它有效:

    On LAMBDA

    为了得到很好的回复,我将返回如下:

    exports.handler = (event, context, callback) => {
        // ..
    
        var someData1 =  {
            data: {
                httpStatusCode: 200,
                details: [
                    {
                        prodId: "123",
                        prodName: "Product 1"
                    },
                    {
                        "more": "213",
                        "moreDetails": "Product 2"
                    }
                ]
            }
        };
        return callback(null, someData1);
    }
    

    如果回复不好,请按以下方式返回

    exports.handler = (event, context, callback) => {
        // ..
    
        var someError1 = {
            error: {
                httpStatusCode: 500,
                details: [
                    {
                        code: "ProductNotFound",
                        message: "Product not found in Cart",
                        description: "Product should be present after checkout, but not found in Cart",
                        source: "/data/attributes/product"
                    },
                    {
                        code: "PasswordConfirmPasswordDoesntMatch",
                        message: "Password and password confirmation do not match.",
                        description: "Password and password confirmation must match for registration to succeed.",
                        source: "/data/attributes/password",
                    }
                ]
            }
        };
    
        return callback(new Error(JSON.stringify(someError1)));
    }
    

    On API Gateway

    对于GET方法,请说/ res1 / service1的GET:

    Through Method Response > Add Response, added 3 responses:
    - 200
    - 300
    - 400
    

    然后,

    Through 'Integration Response' > 'Add integration response', create a Regex for 400 errors (client error):
    
    Lambda Error Regex    .*"httpStatusCode":.*4.*
    
    'Body Mapping Templates' > Add mapping template as:  
        Content-Type                 application/json  
        Template text box*           $input.path('$.errorMessage')  
    
    
    Similarly, create a Regex for 500 errors (server error):
    
    Lambda Error Regex    .*"httpStatusCode":.*5.*
    
    'Body Mapping Templates' > Add mapping template as:  
        Content-Type                 application/json  
        Template text box*           $input.path('$.errorMessage')
    

    现在,发布/ res1 / service1,点击已连接到上述lambda的已发布URL

    使用高级REST客户端(或Postman)chrome插件,您将看到正确的http代码,如服务器错误(500)或400,而不是200 http响应代码,用于“httpStatusCode”中给出的所有请求 .

    在API的“仪表板”中,在API网关中,我们可以看到如下的http状态代码:

  • 1

    这是返回自定义HTTP状态代码和自定义 errorMessage 的最快方法:

    在API网关仪表板中,执行以下操作:

    • 在资源的方法中,单击方法响应

    • 在HTTP状态表中,单击添加响应并添加要使用的每个HTTP状态代码 .

    • 在资源的方法中,单击集成响应

    • 为之前创建的每个HTTP状态代码添加集成响应 . 确保选中输入直通 . 使用lambda错误正则表达式来识别从lambda函数返回错误消息时应使用的状态代码 . 例如:

    // Return An Error Message String In Your Lambda Function
    
    return context.fail('Bad Request: You submitted invalid input');
    
    // Here is what a Lambda Error Regex should look like.
    // Be sure to include the period and the asterisk so any text
    // after your regex is mapped to that specific HTTP Status Code
    
    Bad Request: .*
    
    • 您的API网关路由应该返回:
    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
    • 我认为无法复制这些设置并将其重复用于不同的方法,因此我们有很多烦人的冗余手动输入!

    我的集成响应如下所示:

    aws api gateway lambda error response handling

  • 69

    Update per 20-9-2016

    亚马逊最终使用Lambda Proxy integration轻松实现了这一目标 . 这允许您的Lambda函数返回正确的HTTP代码和标头:

    let response = {
        statusCode: '400',
        body: JSON.stringify({ error: 'you messed up!' }),
        headers: {
            'Content-Type': 'application/json',
        }
    };
    
    context.succeed(response);
    

    在API网关中说再见请求/响应映射!

    Option 2

    使用aws-serverless-express将现有的Express应用程序与Lambda / API Gateway集成 .

  • 1

    我正在使用无服务器0.5 . 就我而言,这就是它的工作原理

    S-function.json:

    {
      "name": "temp-err-test",
      "description": "Deployed",
      "runtime": "nodejs4.3",
      "handler": "path/to/handler.handler",
      "timeout": 6,
      "memorySize": 1024,
      "endpoints": [
        {
          "path": "test-error-handling",
          "method": "GET",
          "type": "AWS_PROXY",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          }
        }
      ]
    }
    

    handler.js:

    'use strict';
    function serveRequest(event, context, cb) {
      let response = {
        statusCode: '400',
        body: JSON.stringify({ event, context }),
        headers: {
          'Content-Type': 'application/json',
        }
      };
      cb(null, response);
    }
    module.exports.handler = serveRequest;
    
  • 4

    如果使用API网关,这是在AWS Compute Blog上推荐的方式 . 检查集成是否与直接Lambda调用一起使用 .

    var myErrorObj = {
        errorType : "InternalServerError",
        httpStatus : 500,
        requestId : context.awsRequestId,
        message : "An unknown error has occurred. Please try again."
    }
    callback(JSON.stringify(myErrorObj));
    

    对于直接Lambda调用,这似乎是客户端解析的最佳解决方案 .

相关问题