web-dev-qa-db-fra.com

API Gateway - Post multipart\form-data

Il semble que ma question soit peut-être un peu similaire à celle-ci .

J'ai une API dans ma passerelle API et je fais un proxy HTTP vers un point de terminaison qui contient les fichiers multipart/form-data de POST.

Si j'appelle le point de terminaison http directement (pas via la passerelle d'API) - en utilisant postman, cela fonctionne normalement, mais l'utilisation du point de terminaison de passerelle API (via postman) échoue.

J'ai comparé les deux requêtes (via les journaux fiddler et CloudWatch) qui semblent identiques:

Demande d'appel direct à l'API (travail):

POST https://domainname/api/v1/documents HTTP/1.1
Host: api.service
Connection: keep-alive
Content-Length: 202
Authorization: AuthToken
Postman-Token: a75869d6-1d64-6b9f-513d-a80ac192c8e1
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
docMetaInfo: some extra data needed
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryB85rsPlMffA2fziS
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

------WebKitFormBoundaryB85rsPlMffA2fziS
Content-Disposition: form-data; name=""; filename="Test.txt"
Content-Type: text/plain

This is a test Text File
------WebKitFormBoundaryB85rsPlMffA2fziS--

Demande de la passerelle API (ne fonctionne pas):

POST https://GATEWAY_domainname/api/v1/documents HTTP/1.1
Host: api-Gateway.service
Connection: keep-alive
Content-Length: 202
Authorization: AuthToken
Postman-Token: e25536fa-3dfa-ddcb-8ca6-3f3552d2bc40
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
docMetaInfo: some extra data needed
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarybX9MyWBsuLGm6QIC

x-api-key: *********************
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

------WebKitFormBoundarybX9MyWBsuLGm6QIC
Content-Disposition: form-data; name=""; filename="Test.txt"
Content-Type: text/plain

This is a test Text File
------WebKitFormBoundarybX9MyWBsuLGm6QIC--

J'ai essayé quelques choses du côté de la passerelle, notamment changer le Integration Request pour mapper un nouveau corps pour le même type de contenu, sans succès.

Autant que je sache, je n'aurais besoin que de passthrough cet appel, ce qui explique pourquoi il devient un peu déroutant - il ne devrait pas être nécessaire de manipuler/intercepter des données?

L'erreur que je reçois est 400 - mauvaise requête (se plaindre du fait que la variable file ne soit pas trouvée), mais comme vous pouvez le voir dans la requête, elle est présente.

Des idées? 

EDIT Journaux de CloudWatch sur le même POST APIGateway

 enter image description here

Erreur toujours 400 - aucun fichier trouvé

15
Hexie

API Gateway ne prend actuellement pas en charge les données de formulaire en plusieurs parties. Ceci est envisagé pour un développement futur. En attendant, vous devrez modifier votre client pour utiliser plusieurs demandes ou une seule demande en une partie.

Mise à jour : API Gateway prend désormais en charge les charges utiles binaires. Définissez simplement "multipart/form-data" comme type de support binaire pour votre API et utilisez le proxy directement dans une fonction Lambda. De là, vous pouvez analyser le corps pour obtenir le contenu de votre fichier. Il devrait y avoir des bibliothèques disponibles pour aider à analyser le corps multipart (parse-multipart dans NodeJS par exemple).

11
RyanG

Il semble y avoir eu un changement et API Gateway n'effectue plus une correspondance stricte de la valeur entière de l'en-tête Content-Type, de sorte que tout fonctionne désormais comme prévu pour la prise en charge "binaire".

Définissez votre API sur POST (ou PUT) et définissez l'intégration Lambda sur "proxy". Accédez aux paramètres de votre API et ajoutez les types de support que vous souhaitez utiliser en tant que "binaire". J'ai ajouté multipart/signed. Le type de média reçu est en fait: Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha256"; boundary="----54645645645664564563424768"

L'API GW continue à le prendre comme "binaire" et le transmet en base64 à mon Lambda.

Dans votre Lambda, vous attraperez alors ceci:

Context:
{
  "callbackWaitsForEmptyEventLoop": true,
  "logGroupName": "/aws/lambda/api-invoice",
  "logStreamName": "2018/04/27/[$LATEST]3454",
  "functionName": "api-invoice",
  "memoryLimitInMB": "128",
  "functionVersion": "$LATEST",
  "invokeid": "345-49e2-11e8-34-345",
  "awsRequestId": "345-49e2-11e8-34-345",
  "invokedFunctionArn": "arn:aws:lambda:eu-west-1:12345:function:api-invoice"
}
-------
Event:
{
  "resource": "/peppol/as2",
  "path": "/peppol/as2",
  "httpMethod": "POST",
  "headers": {
    "Accept": "*/*",
    "AS2-From": "PEPPOL_AP",
    "AS2-To": "234567890",
    "AS2-Version": "1.1",
    "cache-control": "no-cache",
    "Content-Type": "multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=\"sha256\"; boundary=\"----54645645645664564563424768\"",
    "Date": "Fri, 27 Apr 2018 06:17:10 GMT",
    "Disposition-Notification-Options": "signed-receipt-protocol=optional, pkcs7-signature; signed-receipt-micalg=optional, sha1,md5",
    "Disposition-Notification-To": "[email protected]",
    "Host": "123.execute-api.eu-west-1.amazonaws.com",
    "Message-ID": "<[email protected]>",
    "MIME-Version": "1.0",
    "Postman-Token": "ert-59c1-45656-94d1-456546",
    "Recipient-Address": "as2s://123.execute-api.eu-west-1.amazonaws.com/dev/peppol/as2",
    "Subject": "234567890;PEPPOL_AP",
    "User-Agent": "PostmanRuntime/7.1.1",
    "Via": "1.1 ert-",
    "X-Amzn-Trace-Id": "Root=1-4556-ertfd6554",
    "X-CLIENT-IP": "172.17.0.1",
    "X-Forwarded-For": "xx.xxx.xx.80",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "queryStringParameters": null,
  "pathParameters": null,
  "stageVariables": null,
  "requestContext": {
    "resourceId": "80r6gp",
    "resourcePath": "/peppol/as2",
    "httpMethod": "POST",
    "extendedRequestId": "sdsdd343434=",
    "requestTime": "27/Apr/2018:06:17:11 +0000",
    "path": "/dev/peppol/as2",
    "accountId": "123",
    "protocol": "HTTP/1.1",
    "stage": "dev",
    "requestTimeEpoch": 1524809831262,
    "requestId": "354-49e2-3445-b2ba-535345",
    "identity": {
      "cognitoIdentityPoolId": null,
      "accountId": null,
      "cognitoIdentityId": null,
      "caller": null,
      "sourceIp": "xx.xxx.xx.80",
      "accessKey": null,
      "cognitoAuthenticationType": null,
      "cognitoAuthenticationProvider": null,
      "userArn": null,
      "userAgent": "PostmanRuntime/7.1.1",
      "user": null
    },
    "apiId": "123"
  },
  "body": "VGhpcyBpcyBhbiBTL01/ [snip] /S0NCg==",
  "isBase64Encoded": true
}
1
Anders