it-roy-ru.com

API Gateway - Post multipart\form-data

Кажется, мой вопрос может быть немного похож на к этому .

У меня есть API в моем API-шлюзе, и я делаю HTTP-прокси через конечную точку, которая состоит из файлов POST multipart/form-data.

Если я вызываю конечную точку http напрямую (не через шлюз API) - используя почтальон, он работает, как и ожидалось, однако использование конечной точки шлюза API (через почтальон) завершается неудачно.

Я сравнил оба запроса (через журналы Fiddler и CloudWatch), которые кажутся идентичными:

Запрос на прямой вызов API (рабочий):

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

Запрос от шлюза API (не работает):

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

Я попробовал несколько вещей со стороны шлюза, включая изменение Integration Request для сопоставления нового тела для того же типа контента, не повезло.

Насколько я знаю, мне нужно только passthrough этот вызов, поэтому почему он немного сбивает с толку - не должно быть необходимости в манипулировании/перехвате данных?

Я получаю ошибку 400 - неверный запрос (жалуется на то, что file не найден), но, как вы можете видеть в запросе, он есть.

Есть идеи? 

EDIT Журналы из CloudWatch на том же APIGateway POST

enter image description here

Ошибка все еще 400 - файл не найден

15
Hexie

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

Обновление : API Gateway теперь поддерживает двоичные полезные данные. Просто определите «multipart/form-data» как двоичный медиа-тип для вашего API и передайте полезную нагрузку непосредственно в функцию Lambda. Оттуда вы можете проанализировать тело, чтобы получить содержимое вашего файла. Должны быть доступны библиотеки, которые помогут разобрать составное тело (например, 'parse-multipart' в NodeJS).

11
RyanG

Похоже, что произошли изменения, и API Gateway больше не выполняет строгое сопоставление всего значения заголовка Content-Type, поэтому теперь все для «двоичной» поддержки работает должным образом.

Установите для своего API значение POST (или PUT) и установите для интеграции Lambda значение «proxy». Перейдите в настройки своего API и добавьте типы мультимедиа, которые вы хотите использовать как «двоичные». Я добавил multipart/signed. Полученный тип носителя: Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha256"; boundary="----54645645645664564563424768"

API GW по-прежнему воспринимает это как «двоичный» и доставляет его как base64 на мою Lambda.

В вашей лямбде вы поймаете это:

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

У меня была такая же проблема при интеграции с моим сервером Tomcat, я обнаружил ниже изменения, необходимые для ее исправления.

  1. Добавьте Content-Type в вашем API Заголовки HTTP-запросов в API-шлюз через консоль или добавьте его в документацию открытого API, как 

    {
        "/yourApi":{
            "post":{
                "operationId":"uploadImageUsingPOST",
                "produces":[
                    "application/json"
                ],
                "parameters":[
                {
                    "name":"Content-Type",
                    "in":"header",
                    "required":false,
                    "type":"string"
                },
                {
                    //Other headers
                }]   
            }
        }
    
  2. Выше шага также добавьте Content-Type в HTTP-заголовки вашего API-интерфейса интеграции, если не добавите его туда, добавьте еще один заголовок Accept = '/' в шлюз api через консоль или или добавьте его в открыть документацию API, как

    "requestParameters":{
        "integration.request.header.Accept":"'*/*'",
        "integration.request.header.Content-Type":"method.request.header.Content-Type",
        //Other headers
    }
    
  3. Установите Content Handling as Passthrough в запросе интеграции вашего API.

  4. Добавьте multipart/form-data как Binary Media Types в настройках вашего API через консоль или через открытую документацию API.

    "x-Amazon-apigateway-binary-media-types": [
        "multipart/form-data"
    ]
    
  5. Разверните вышеупомянутые изменения на желаемом этапе, когда вы собираетесь загрузить изображение как составное.

Api-шлюз передаст ваш многокомпонентный файл как двоичный массив, и вы все равно можете использовать @RequestBody MultipartFile multipartFile в своем контроллере, а Spring проанализирует этот двоичный файл как многочастный для вас.

0
Swalih