Есть ли способ изменить коды состояния http, возвращаемые Amazon API Gateway?


например, если я хочу вернуть конкретную ошибку 400 для недопустимых параметров или, возможно, 201, когда вызов лямбда-функции привел к созданию.

Я хотел бы иметь разные коды состояния http, но похоже, что api gateway всегда возвращает код состояния 200, даже если функция lambda возвращает ошибку.

9 69

9 ответов:

обновление за 20-9-2016

Amazon, наконец, сделал это легко с помощью интеграция лямбда Прокси. Это позволяет вашей лямбда-функции возвращать правильные HTTP-коды и заголовки:

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

context.succeed(response);

попрощайтесь с отображением запроса / ответа в шлюзе API!

2

интеграция существующего Экспресс-приложения с Lambda / API Gateway с помощью aws-serverless-express.

вот самый быстрый способ вернуть пользовательские коды состояния HTTP и пользовательский errorMessage:

на панели мониторинга шлюза API выполните следующие действия:

  1. на метод для ресурс, нажмите кнопку способ ответа
  2. на HTTP статус "таблица", нажмите кнопку добавить ответ и добавьте в каждый код состояния HTTP, который вы хотели бы использовать.
  3. на метод для ваш ресурс, нажмите кнопку интеграция ответ
  4. добавить интеграция ответ для каждого из кодов состояния HTTP, созданных ранее. Убедитесь, что ввод passthrough это. Используйте регулярное выражение ошибки лямбда чтобы определить, какой код состояния следует использовать при возврате сообщения об ошибке из лямбда-функции. Например:

    // 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 должен верните это:

    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
  6. Я не вижу способа скопировать эти настройки и повторно использовать их для разных методов, поэтому у нас есть много раздражающих избыточных ручных вводов!

мои ответы интеграции выглядят так:

aws api gateway lambda error response handling

чтобы иметь возможность возвращать пользовательский объект ошибки как JSON, вам нужно перепрыгнуть через пару обручей.

во-первых, вы должны отказать лямбда и передать ему строковый объект 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:

.*"статус":400.*

наконец, вы устанавливаете шаблон сопоставления для извлечения ответ JSON из свойства errorMessage, возвращенного лямбда-выражением. Шаблон отображения выглядит следующим образом:

$input.путь.$'(сообщение об ошибке')

Я написал статью об этом, которая более подробно объясняет поток ответов от Lambda до API Gateway здесь: http://kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object-and-status-code-from-api-gateway-with-lambda/

1) настройка ресурса шлюза API для использования Интеграция Лямбда Прокси установив флажок "использовать интеграцию лямбда Прокси" на экране "запрос на интеграцию"определения ресурса шлюза API. (Или определите его в своей конфигурации cloudformation/terraform/serverless/etc)

2) измените свой лямбда-код двумя способами

  • обрабатывать входящие event (1-й функции аргумент) соответственно. Это уже не просто голая полезная нагрузка, она представляет весь HTTP-запрос, включая заголовки, строку запроса и тело. Пример ниже. Ключевым моментом является то, что тела JSON будут строками, требующими явного JSON.parse(event.body) звоните (не забудьте try/catch вокруг этого). Пример приведен ниже.
  • ответьте, вызвав обратный вызов с null, а затем объект ответа, который предоставляет сведения HTTP, включая statusCode,body и headers.
    • body должно быть строка, так что JSON.stringify(payload) по мере необходимости
    • statusCode может быть числом
    • headers является объектом заголовочных имен для значений

пример аргумента лямбда-события для интеграции Прокси

{
    "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 обратного вызова-это правильная вещь в будущем.

для тех, кто пробовал все поставить на этот вопрос и не мог сделать эту работу (как я), проверьте комментарий thedevkit на этом посту (спас мой день):

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

воспроизводить его полностью ниже:

У меня были проблемы с этим сам, и я считаю, что новая строка виноваты персонажи.

фу.* будет соответствовать вхождениям "foo" с последующим любым письмена Кроме новой строки. Обычно это решается путем добавления флага' /s', т. е. "foo.* / s", но регулярное выражение ошибки лямбда, похоже, не уважает это.

в качестве альтернативы вы можете использовать что-то вроде: Фу(.|\n)*

Я хотел, чтобы ошибка от лямбда была правильной ошибкой 500, после проведения большого количества исследований, придумал ниже, что работает:

на лямбда

для хорошего ответа, я возвращаюсь, как показано ниже:

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

для метода GET, скажем GET of /res1 / service1:

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')  

теперь, publish /res1 / service1, нажмите опубликованный URL, который подключен к выше лямбда

используется расширенный клиент REST (или почтальон) Chrome плагин, вы увидите правильные http-коды, такие как ошибка сервера (500) или 400, вместо 200 http-код ответа для всех запросов, где были даны в "httpStatusCode".

из "приборной панели" API, в API Gateway, мы можем увидеть коды состояния http, как показано ниже:

400 & 500 errors

самый простой способ сделать это - использовать интеграцию LAMBDA_PROXY. Используя этот метод, вам не нужно никаких специальных преобразований для установки в конвейер шлюза 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
};

у него есть несколько недостатков: как необходимость быть особенно осторожным в обработке ошибок и связывать свою лямбда-функцию с конечной точкой шлюза API; тем не менее, если вы действительно не собираетесь ее использовать нигде, это не такая уж большая проблема.

Я использую serverless 0.5. Вот как это работает, для моего случая

s-функции.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"
        }
      }
    }
  ]
}

обработчик.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;

вот как это рекомендуется в блоге AWS Compute при использовании API Gateway. Проверка, работает ли интеграция с прямым вызовом лямбда.

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

для прямых лямбда-вызовов это, по-видимому, лучшее решение для анализа на стороне клиента.