Amazon API Gateway tarafından döndürülen http durum kodlarını değiştirmenin bir yolu var mı?


97

Örneğin, geçersiz parametreler için belirli bir 400 hatası veya lambda işlevi çağrısı bir oluşturma ile sonuçlandığında bir 201 döndürmek istersem.

Farklı http durum kodlarına sahip olmak istiyorum, ancak lambda işlevi bir hata döndürse bile api ağ geçidinin her zaman bir 200 durum kodu döndürdüğü görülüyor.


2
bu yüzden, karşılaştığım sorun, özel bir hata türü döndürüyormuşum gibi görünüyor - bu da errorMessage regex'in doğru çalışmamasına neden oluyor. Lambda'dan gelen hata yanıtında standart bir dizge döndürmek aşağıdaki çözümün çalışmasını sağlar - ancak kendi özel hata nesnenizi döndürmek işe yaramaz.
MonkeyBonkey

benim çözümüm, Serveless sürüm 0.5'ten 1.0'a geçmekti. Ayrıca, yanıt nesnesinde statusCode'u bir özellik olarak belirterek, Serveless belgelerden gelen yanıtı kullanıyorum. Umarım yardımcı olur
Relu Mesaros

Yanıtlar:


79

20-9-2016'ya göre güncelleme

Amazon, Lambda Proxy entegrasyonunu kullanarak nihayet bunu kolaylaştırdı . Bu, Lambda işlevinizin doğru HTTP kodlarını ve başlıklarını döndürmesine olanak tanır:

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

context.succeed(response);

API Ağ Geçidinde istek / yanıt eşlemesine elveda deyin!

seçenek 2

Mevcut bir Express uygulamasını, aws-serverless-express kullanarak Lambda / API Ağ Geçidi ile entegre edin .


1
Entegre edemiyorum, yani 200 durumu ve oluşturulan yanıtı (oluşturulan hata) alıyorum. Bir şey mi kaçırıyorum? "S-function.json" nasıl görünüyor?
Relu Mesaros

7
Merak eden herkes için bu, yeni callbackstil kullanılarak da sağlanabilir . Sadece yap callback(null, {statusCode: 200, body: 'whatever'}).
Widdershin

1
@unclemeat Aynı sorularım var. Bunu çözebildin mi? Bunu python'da nasıl yapabilirim?
Sushil

1
@Sushil evet, JSON'u yukarıdaki yanıt değişkeninde olduğu gibi döndürüyorsunuz.
unclemeat

8
@Sushil Bunu Python'da LambdaProxyIntegration ile çözdüm ve geri döndümreturn { "isBase64Encoded": True, "statusCode": 200, "headers": { }, "body": "" }
Jithu R Jacob

74

Özel HTTP Durum Kodlarını ve özel bir özelliğe döndürmenin en hızlı yolu errorMessage:

API Ağ Geçidi kontrol panelinde aşağıdakileri yapın:

  1. In yöntemle sizin için kaynak , tıklayabilir yöntem tepkisi
  2. Gelen HTTP Durum tablosunun tıklayın eklenti yanıtı ve kullanmak istediğiniz her HTTP Status Code ekleyin.
  3. In yöntemle sizin için kaynak , tıklayın entegrasyon tepkisi
  4. Daha önce oluşturduğunuz HTTP Durum Kodlarının her biri için bir entegrasyon yanıtı ekleyin . Giriş geçişinin işaretlendiğinden emin olun . Lambda işlevinizden bir hata mesajı döndürdüğünüzde hangi durum kodunun kullanılması gerektiğini belirlemek için lambda hata normal ifadesini kullanın . Örneğin:

    // 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 Ağ Geçidi rotanız şunu döndürmelidir:

    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
  6. Bu ayarları kopyalamanın ve farklı yöntemler için yeniden kullanmanın bir yolunu göremiyorum, bu yüzden yapmamız gereken çok fazla sinir bozucu manuel girişimiz var!

Entegrasyon Yanıtlarım şuna benzer:

aws api ağ geçidi lambda hatası yanıtı işleme


3
bu yüzden benim sorunum, sadece bir dize yerine lambda'dan bir hata nesnesi döndürdüğüm için normal ifade tetikleyicisinin hiç çalışmamasıydı. örneğinreturn context.fail(new Error('bad one'))
MonkeyBonkey

7
@kalisjoshua Kısa süre önce API Gateway / Lambda ile hata işleme hakkında oldukça ayrıntılı bir gönderi yayınladım: jayway.com/2015/11/07/…
Carl

9
Python Lambda'lar için context.fail'in eşdeğeri nedir?
routeeburn

1
Python için: bir İstisna oluşturun. Bkz. Docs.aws.amazon.com/lambda/latest/dg/python-exceptions.html
devxoul

1
Hatasız yanıtlarda durum kodunu değiştirmenin bir yolu yok mu? Oluşturulan nesneyle birlikte "201 Oluşturuldu" göndermek istersem ne olur?
Ben Davis

18

Özel bir hata nesnesini JSON olarak döndürebilmek için birkaç çemberden geçmeniz gerekir.

İlk olarak, Lambda'da başarısız olmanız ve ona dizgeleştirilmiş bir JSON nesnesi iletmeniz gerekir:

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

Ardından, döndürmek istediğiniz her bir durum kodu için normal ifade eşlemesini ayarlarsınız. Yukarıda tanımladığım nesneyi kullanarak bu regex'i 400 için kurarsınız:

. * "durum": 400. *

Son olarak, JSON yanıtını Lambda tarafından döndürülen errorMessage özelliğinden çıkarmak için bir Eşleme Şablonu kurarsınız. Eşleme Şablonu şuna benzer:

$ input.path ('$. errorMessage')

Bununla ilgili daha ayrıntılı bilgi veren ve burada Lambda'dan API Ağ Geçidine yanıt akışını açıklayan bir makale yazdım: http://kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object -and-status-code-from-api-gateway-with-lambda /


@kennbrodhagen API Gateway ve Java Lambdas hakkında bilginiz var mı? Bir tür aynı reg exp kullanıyorum ve bu benim için çalışmıyor. Kullanıyorum. * StatusCode ": 422. *
Perimosh

@Perimosh, bunun Java İstisnaları ile nasıl yapılacağını açıklayan bu makaleye göz atın
kennbrodhagen

10

1) API Ağ Geçidi kaynak tanımının "Entegrasyon İsteği" ekranındaki " Lambda Proxy entegrasyonunu kullan" etiketli onay kutusunu işaretleyerek API Ağ Geçidi kaynağınızı Lambda Proxy Entegrasyonunu kullanacak şekilde yapılandırın . (Veya cloudformation / terraform / serverless / etc yapılandırmanızda tanımlayın)

2) Lambda kodunuzu 2 şekilde değiştirin

  • Gelen event(1. işlev bağımsız değişkeni) uygun şekilde işleyin . Artık yalnızca yük değil, başlıklar, sorgu dizesi ve gövde dahil tüm HTTP isteğini temsil ediyor. Aşağıdaki örnek. Kilit nokta, JSON gövdelerinin açık JSON.parse(event.body)çağrı gerektiren dizeler olacağıdır (bunu unutmayınız try/catch). Örnek aşağıdadır.
  • Daha sonra boş dahil olmak üzere HTTP bilgilerini sağlayan bir yanıt nesnesiyle geri arama çağırarak yanıt statusCode, bodyve headers.
    • bodybir dize olmalı, gerektiği JSON.stringify(payload)gibi yap
    • statusCode bir sayı olabilir
    • headers değerlere başlık adlarının bir nesnesidir

Proxy Entegrasyonu için Örnek Lambda Olay Argümanı

{
    "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
}

Örnek Geri Arama Yanıt Şekli

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

Notlar - contextGibi yöntemlerin context.succeed()kullanımdan kaldırıldığına inanıyorum . Hala işe yarıyor gibi görünseler de artık belgelenmiyorlar. Geri arama API'sine kodlamanın ileriye dönük doğru şey olduğunu düşünüyorum.


1
Bu çalışmıyor. Hala bu yanıt çıktısının tamamı ile döndürülen 200 durumu alıyorum. API gerçekten 409 durumuna dönecek şekilde ayarlanamıyor
Andy N

7

Lambda'dan bir hatanın uygun bir 500 hatası olmasını istedim, çok fazla araştırma yaptıktan sonra aşağıdakileri buldum, bu işe yarıyor:

LAMBDA'da

İyi bir yanıt için aşağıdaki gibi geri dönüyorum:

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

Kötü bir yanıt için aşağıdaki gibi geri dönüyoruz

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 Ağ Geçidinde

GET YÖNTEMİ için, GET of / res1 / service1 deyin:

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

Sonra,

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

Şimdi, / res1 / service1 yayınla, yukarıdaki lambda'ya bağlı yayınlanan URL'yi tıklayın

Gelişmiş REST istemcisi (veya Postman) krom eklentisi kullanıldığında, "httpStatusCode" da verilen tüm istekler için 200 http yanıt kodu yerine, sunucu hatası (500) veya 400 gibi uygun http kodlarını göreceksiniz.

API Gateway'deki API 'Dashboard'dan, aşağıdaki gibi http durum kodlarını görebiliriz:

400 ve 500 hata


7

Bunu yapmanın en kolay yolu LAMBDA_PROXY entegrasyonunu kullanmaktır . Bu yöntemi kullanarak, API Ağ Geçidi ardışık düzenine ayarlanacak özel dönüşümlere ihtiyacınız yoktur.

Dönüş nesneniz aşağıdaki parçacığa benzer olmalıdır:

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

Birkaç dezavantajı vardır: hata işleme konusunda özellikle dikkatli olmak ve lambda işlevinizi API Ağ Geçidi uç noktasına bağlamak; bu, gerçekten başka bir yerde kullanmayacak olsaydınız, bu o kadar da büyük bir sorun olmadığını söyledi.


6

Bu soruya sorulan her şeyi deneyen ve bu işi yapamayanlar için (benim gibi), bu yazıdaki thedevkit yorumuna bakın (günümü kurtardı)

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

Tamamen aşağıda yeniden üretiliyor:

Bununla kendim de sorunlar yaşadım ve suçluların satırsonu karakterleri olduğuna inanıyorum.

foo. * "foo" ve ardından satırsonu HARİÇ herhangi bir karakter ile eşleşir. Tipik olarak bu, "/ s" bayrağı, yani "foo. * / S" eklenerek çözülür, ancak Lambda hata normal ifadesi buna uymuyor gibi görünüyor.

Alternatif olarak aşağıdaki gibi bir şey kullanabilirsiniz: foo (. | \ N) *


harika bul! Bana saatlerce kafamı çarptı! Ve bariz olmaktan çok uzak.
Mirko Vukušić

Mirko, sana yardım ettiğine sevindim!
Carlos Ballock

2

API Gateway kullanılıyorsa bir AWS Compute Blogunda bu şekilde önerilir. Entegrasyonun doğrudan Lambda çağrısıyla çalışıp çalışmadığını kontrol etme.

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

Doğrudan Lambda çağrıları için bu, istemci tarafında ayrıştırmanın en iyi çözümü gibi görünüyor.


ya örnek lambda'dan lambda'ya çağrı ise. bu hala lambda denen şeyin geri döneceği şey mi? ve çağıran lambda üzerindeki httpStatus'u nasıl okuyabilirim.
Çubuk

1

Sunucusuz 0.5 kullanıyorum. Benim durumum için işler böyle

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

Proxy kullanmak istemiyorsanız, bu şablonu kullanabilirsiniz:

#set($context.responseOverride.status =  $input.path('$.statusCode'))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.