Amazon API Gateway에서 반환 한 http 상태 코드를 변경하는 방법이 있습니까?


95

예를 들어 잘못된 매개 변수에 대해 특정 400 오류를 반환하거나 람다 함수 호출로 인해 생성이 발생했을 때 201을 반환하려는 경우.

다른 http 상태 코드를 갖고 싶지만 람다 함수가 오류를 반환하더라도 api 게이트웨이가 항상 200 상태 코드를 반환하는 것처럼 보입니다.


2
그래서 내가 가지고 있던 문제는 사용자 정의 오류 유형을 반환한다는 것입니다-errorMessage 정규식이 올바르게 작동하지 않게합니다. 람다의 실패 응답에서 표준 문자열을 반환하면 아래 솔루션이 작동합니다. 그러나 사용자 지정 오류 개체를 반환하면 작동하지 않습니다.
MonkeyBonkey

내 해결책은 Serveless 버전 0.5에서 1.0으로 전환하는 것이 었습니다. 또한 응답 개체의 statusCode를 속성으로 지정하여 Serveless 문서의 응답을 사용하고 있습니다. 희망은 도움이
Relu Mesaros

답변:


79

2016 년 9 월 20 일에 업데이트

Amazon은 마침내 Lambda 프록시 통합을 사용하여이를 쉽게 만들었습니다 . 이를 통해 Lambda 함수가 적절한 HTTP 코드 및 헤더를 반환 할 수 있습니다.

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

context.succeed(response);

API Gateway에서 작별 요청 / 응답 매핑!

옵션 2

aws-serverless-express를 사용하여 기존 Express 앱을 Lambda / API Gateway와 통합합니다 .


통합 할 수 없습니다. 200 개의 상태와 생성 된 응답 (생성 된 오류)을 얻습니다. 내가 뭔가를 놓치고 있습니까? "s-function.json"은 어떻게 생겼습니까?
Relu Mesaros

가장 간단한 예는 microservice-http-endpoint (AWS Lambda 콘솔에서)라는 AWS 자체 Lambda 청사진을 참조하십시오. 서버리스 프레임 워크 ( serverless.com )를 사용하는 것처럼 들리는 "s-function.json"을 언급 합니다. 이것은 완전히 또 다른 야수이며 aws-serverless-express 또는 'raw'Lambda / API Gateway와 혼동해서는 안됩니다. 내 대답은 서버리스 프레임 워크를 사용하여이 작업을 수행하는 방법을 설명하지 않습니다.
Eric Eijkelenboom

7
궁금한 사람은 새로운 callback스타일을 사용하여이 작업을 수행 할 수도 있습니다 . 그냥하세요 callback(null, {statusCode: 200, body: 'whatever'}).
Widdershin

1
@Sushil 예, 위의 응답 변수에서와 같이 JSON을 반환합니다.
unclemeat

8
나는 LambdaProxyIntegration 파이썬에서이 문제를 해결하고 돌아왔다 @Sushilreturn { "isBase64Encoded": True, "statusCode": 200, "headers": { }, "body": "" }
Jithu R 야곱을

74

사용자 지정 HTTP 상태 코드 및 사용자 지정을 반환하는 가장 빠른 방법은 다음과 같습니다 errorMessage.

API Gateway 대시 보드에서 다음을 수행합니다.

  1. 에서 방법 당신을위한 자원 , 클릭 방법 응답
  2. 에서 HTTP 상태 표, 클릭 추가 응답을 당신이 사용하고자하는 각각의 HTTP 상태 코드에 추가 할 수 있습니다.
  3. 에서 방법 당신을위한 자원 , 클릭 통합 응답
  4. 이전에 생성 한 각 HTTP 상태 코드에 대한 통합 응답 을 추가합니다 . 입력 패스 스루 가 선택되어 있는지 확인하십시오 . 사용 람다 오류 정규식은 당신이 당신의 람다 함수에서 오류 메시지를 반환 할 때 사용되어야하는 상태 코드를 식별합니다. 예를 들면 :

    // 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: .*
    
  5. API Gateway 경로는 다음을 반환해야합니다.

    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
  6. 이 설정을 복사하여 다른 방법으로 재사용 할 수있는 방법이 없습니다. 그래서 우리는 할 일이 많은 성가신 중복 수동 입력이 있습니다!

내 통합 응답은 다음과 같습니다.

aws api gateway lambda 오류 응답 처리


3
그래서 내 문제는 문자열이 아닌 fail 메서드에서 람다에서 오류 개체를 반환하기 때문에 정규식 트리거가 작동하지 않는 것 같습니다. 예return context.fail(new Error('bad one'))
MonkeyBonkey 2015

7
@kalisjoshua 최근 API Gateway / Lambda를 사용한 오류 처리에 대한 자세한 게시물을 게시했습니다. jayway.com/2015/11/07/…
Carl

9
Python Lambda의 context.fail에 해당하는 것은 무엇입니까?
routeburn 2015

1
파이썬의 경우 : 예외를 발생시킵니다. 참조 docs.aws.amazon.com/lambda/latest/dg/python-exceptions.html
devxoul

1
오류가 아닌 응답에서 상태 코드를 변경할 수있는 방법이 없습니까? 생성 된 개체와 함께 "201 Created"를 보내려면 어떻게해야합니까?
벤 데이비스

18

사용자 지정 오류 개체를 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 -및 상태 코드-람다와 함께 API 게이트웨이에서 /


@kennbrodhagen API Gateway 및 Java Lambda에 대해 알고 있습니까? 나는 일종의 동일한 reg exp를 사용하고 있는데 그것은 나를 위해 작동하지 않습니다. . * statusCode ":
422.

: @Perimosh 자바 예외와 함께이 작업을 수행하는 방법에 대해 설명이 문서 확인 aws.amazon.com/blogs/compute/...
kennbrodhagen

10

1) API Gateway 리소스 정의의 "통합 요청"화면에서 " Lambda 프록시 통합 사용" 확인란을 선택 하여 Lambda 프록시 통합 을 사용하도록 API Gateway 리소스를 구성합니다 . (또는 cloudformation / terraform / serverless / etc 구성에서 정의하십시오)

2) 두 가지 방법으로 람다 코드 변경

  • 들어오는 event(첫 번째 함수 인수)를 적절하게 처리합니다. 더 이상 베어 페이로드가 아니라 헤더, 쿼리 문자열 및 본문을 포함한 전체 HTTP 요청을 나타냅니다. 아래 샘플. 요점은 JSON 본문이 명시 적 JSON.parse(event.body)호출이 필요한 문자열이라는 것입니다 (그것을 잊지 마세요 try/catch). 예는 다음과 같습니다.
  • null를 포함한 HTTP 정보를 제공하는 응답 객체와 콜백을 호출하여 응답 statusCode, bodyheaders.
    • body문자열이어야하므로 필요 JSON.stringify(payload)에 따라 수행하십시오.
    • statusCode 숫자가 될 수 있습니다
    • 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'
  }
})

참고 - 난에 방법을 생각 context등이로 context.succeed()사용되지 않습니다. 여전히 작동하는 것처럼 보이지만 더 이상 문서화되지 않습니다. 콜백 API로 코딩하는 것이 앞으로도 올바른 것이라고 생각합니다.


작동하지 않습니다. 이 전체 응답 출력과 함께 여전히 200 개의 상태가 반환됩니다. 실제로 409 상태를 반환하도록 API를 설정할 수 없음
Andy N

7

나는 Lambda의 오류가 적절한 500 오류가되기를 원했습니다. 많은 연구를 한 후 다음과 같이 작동했습니다.

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)));
}

API Gateway에서

GET METHOD의 경우 / 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을 게시하고 위의 람다에 연결된 게시 된 URL을 누릅니다.

고급 REST 클라이언트 (또는 Postman) 크롬 플러그인을 사용하면 "httpStatusCode"에 제공된 모든 요청에 ​​대해 200 http 응답 코드 대신 서버 오류 (500) 또는 400과 같은 적절한 http 코드가 표시됩니다.

API의 'Dashboard'에서 API Gateway의 다음과 같은 http 상태 코드를 볼 수 있습니다.

400 및 500 오류


7

이를 수행하는 가장 쉬운 방법은 LAMBDA_PROXY 통합사용하는 것 입니다. 이 방법을 사용하면 API Gateway 파이프 라인으로 설정하는 데 특별한 변환이 필요하지 않습니다.

반환 객체는 아래 스 니펫과 유사해야합니다.

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
};

여기에는 몇 가지 단점이 있습니다. 오류 처리에 대해 특별히주의해야하고 람다 함수를 API 게이트웨이 엔드 포인트에 연결해야한다는 점입니다. 즉, 다른 곳에서 실제로 사용하지 않을 경우 그다지 문제가되지 않습니다.


6

이 질문에 대한 모든 것을 시도했지만 (나처럼)이 작업을 수행 할 수없는 사람들은이 게시물에 대한 thedevkit 주석을 확인하십시오 (내 하루를 저장했습니다).

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

전체적으로 아래에서 재현 :

나는 이것과 관련하여 문제가 있었고 개행 문자가 범인이라고 생각합니다.

foo. *는 "foo"다음에 개행 문자를 제외한 모든 문자와 일치합니다. 일반적으로이 문제는 '/ s'플래그, 즉 "foo. * / s"를 추가하여 해결되지만 Lambda 오류 정규식은이를 존중하지 않는 것 같습니다.

대안으로 다음과 같은 것을 사용할 수 있습니다 : foo (. | \ n) *


놀라운 발견! 그것은 내 머리를 두드리는 시간을 절약했습니다! 그리고 그것은 명백하지 않습니다.
Mirko Vukušić

Mirko, 도움이되어 기쁩니다!
Carlos Ballock 17.02.15

2

이것이 API Gateway를 사용하는 경우 AWS 컴퓨팅 블로그에서 권장되는 방법입니다. 통합이 직접 Lambda 호출과 함께 작동하는지 확인합니다.

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

직접 Lambda 호출의 경우 이는 클라이언트 측에서 구문 분석하는 최상의 솔루션 인 것으로 보입니다.


예제가 람다에서 람다로의 호출이면 어떨까요? 이것은 여전히 ​​호출 된 람다가 반환 할 것입니까? 호출 람다에서 httpStatus를 어떻게 읽을 수 있습니까?
Rod

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;

1

프록시를 사용하지 않으려면 다음 템플릿을 사용할 수 있습니다.

#set($context.responseOverride.status =  $input.path('$.statusCode'))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.