API 网关 - POST multipart/form-data
API Gateway - POST multipart/form-data
看来我的问题可能有点类似to this one。
我的 API Gateway
中有一个 API,我正在通过 HTTP 代理连接到 POST 的 multipart/form-data
文件的端点。
如果我直接调用 HTTP 端点(不通过 API gateway
)- 使用 postman
,它会按预期工作,但是,使用 API 网关端点(通过 postman
) 失败。
我比较了两个请求(通过 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
未找到),但正如您在请求中看到的那样,它就在那里。
有什么想法吗?
编辑
来自同一 API 网关 POST
上的 CloudWatch 的日志
错误仍然是 400 - 找不到文件
API 网关目前不支持多部分表单数据。这正在考虑用于未来的发展。同时,您需要修改客户端以使用多个请求或单个 one-part 请求。
更新:API 网关现在支持二进制负载。只需将 multipart/form-data
定义为 API 的二进制媒体类型,并将负载直接代理到 Lambda 函数。从那里您可以解析正文以获取文件内容。应该有可用的库来帮助解析多部分正文(例如 Node.js 中的 parse-multipart)。
似乎发生了变化,API 网关不再对整个 Content-Type header 值进行严格匹配,因此现在支持 "binary" 的所有内容按预期工作。
将您的 API 设置为 POST(或 PUT)并将 Lambda 集成设置为 "proxy"。转到 API 的设置并添加要用作 "binary" 的媒体类型。我添加了 multipart/signed
。
接收到的媒体类型实际上是:
Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha256"; boundary="----54645645645664564563424768"
API GW 仍然将其作为 "binary" 提取,并将其作为 base64 传递给我的 Lambda。
在您的 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": "ignored@example.com",
"Host": "123.execute-api.eu-west-1.amazonaws.com",
"Message-ID": "<456-9d44-4c61-456-456546@172.17.0.3>",
"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
}
我在与 tomcat 服务器集成时遇到了同样的问题,我发现需要进行以下更改才能修复它。
在您的 api 的 HTTP 请求中添加 Content-Type Headers 通过控制台在 api 网关中或将其添加到打开的 api 文档中,例如
{
"/yourApi":{
"post":{
"operationId":"uploadImageUsingPOST",
"produces":[
"application/json"
],
"parameters":[
{
"name":"Content-Type",
"in":"header",
"required":false,
"type":"string"
},
{
//Other headers
}]
}
}
上面的步骤也在你的api的集成请求的HTTPHeaders中添加Content-Type,如果没有也添加它并添加一个header 通过控制台在 api 网关中接受 ='/' 或将其添加到打开的 api 文档中,例如
"requestParameters":{
"integration.request.header.Accept":"'*/*'",
"integration.request.header.Content-Type":"method.request.header.Content-Type",
//Other headers
}
在您的 api 集成请求中将内容处理设置为直通。
通过控制台或打开 api 文档
在 api 的设置中添加 multipart/form-data 作为二进制媒体类型
"x-amazon-apigateway-binary-media-types": [
"multipart/form-data"
]
将以上更改部署到您要将图像作为多部分上传的所需阶段。
Api 网关会将您的多部分文件作为二进制数组传递,您仍然可以在控制器中使用 @RequestBody MultipartFile multipartFile,spring 将为您将此二进制文件解析为多部分。
对于那些仍然需要帮助的人,现在正式记录了这一点:
总结一下,步骤如下:
- 转到 API 网关设置选项卡 API 并将
multipart/form-data
添加到 二进制媒体类型 部分。
- 将
Content-Type
和 Accept
添加到您的代理方法的请求 headers
- 将相同的 headers 添加到集成请求中 headers
- Re-deploy API
已解决:https://github.com/mscdex/busboy/issues/199#issuecomment-505239005
我在 node.js
中为 multipart-form-data 使用 express-fileupload
然后仅在 AWS API 网关上配置设置
Select API => 设置 => 二进制媒体类型 =>
现在没有损坏 formdata 中的任何文件,一切正常。
使用 AWS 从服务器上传和检索图像 API Gateway Proxy+ 和 Lambda
通过 AWS 网关和 lambda 代理上传和检索图像以及管理二进制数据的代码示例+
看来我的问题可能有点类似to this one。
我的 API Gateway
中有一个 API,我正在通过 HTTP 代理连接到 POST 的 multipart/form-data
文件的端点。
如果我直接调用 HTTP 端点(不通过 API gateway
)- 使用 postman
,它会按预期工作,但是,使用 API 网关端点(通过 postman
) 失败。
我比较了两个请求(通过 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
未找到),但正如您在请求中看到的那样,它就在那里。
有什么想法吗?
编辑 来自同一 API 网关 POST
上的 CloudWatch 的日志错误仍然是 400 - 找不到文件
API 网关目前不支持多部分表单数据。这正在考虑用于未来的发展。同时,您需要修改客户端以使用多个请求或单个 one-part 请求。
更新:API 网关现在支持二进制负载。只需将 multipart/form-data
定义为 API 的二进制媒体类型,并将负载直接代理到 Lambda 函数。从那里您可以解析正文以获取文件内容。应该有可用的库来帮助解析多部分正文(例如 Node.js 中的 parse-multipart)。
似乎发生了变化,API 网关不再对整个 Content-Type header 值进行严格匹配,因此现在支持 "binary" 的所有内容按预期工作。
将您的 API 设置为 POST(或 PUT)并将 Lambda 集成设置为 "proxy"。转到 API 的设置并添加要用作 "binary" 的媒体类型。我添加了 multipart/signed
。
接收到的媒体类型实际上是:
Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha256"; boundary="----54645645645664564563424768"
API GW 仍然将其作为 "binary" 提取,并将其作为 base64 传递给我的 Lambda。
在您的 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": "ignored@example.com",
"Host": "123.execute-api.eu-west-1.amazonaws.com",
"Message-ID": "<456-9d44-4c61-456-456546@172.17.0.3>",
"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
}
我在与 tomcat 服务器集成时遇到了同样的问题,我发现需要进行以下更改才能修复它。
在您的 api 的 HTTP 请求中添加 Content-Type Headers 通过控制台在 api 网关中或将其添加到打开的 api 文档中,例如
{ "/yourApi":{ "post":{ "operationId":"uploadImageUsingPOST", "produces":[ "application/json" ], "parameters":[ { "name":"Content-Type", "in":"header", "required":false, "type":"string" }, { //Other headers }] } }
上面的步骤也在你的api的集成请求的HTTPHeaders中添加Content-Type,如果没有也添加它并添加一个header 通过控制台在 api 网关中接受 ='/' 或将其添加到打开的 api 文档中,例如
"requestParameters":{ "integration.request.header.Accept":"'*/*'", "integration.request.header.Content-Type":"method.request.header.Content-Type", //Other headers }
在您的 api 集成请求中将内容处理设置为直通。
通过控制台或打开 api 文档
在 api 的设置中添加 multipart/form-data 作为二进制媒体类型"x-amazon-apigateway-binary-media-types": [ "multipart/form-data" ]
将以上更改部署到您要将图像作为多部分上传的所需阶段。
Api 网关会将您的多部分文件作为二进制数组传递,您仍然可以在控制器中使用 @RequestBody MultipartFile multipartFile,spring 将为您将此二进制文件解析为多部分。
对于那些仍然需要帮助的人,现在正式记录了这一点:
总结一下,步骤如下:
- 转到 API 网关设置选项卡 API 并将
multipart/form-data
添加到 二进制媒体类型 部分。 - 将
Content-Type
和Accept
添加到您的代理方法的请求 headers - 将相同的 headers 添加到集成请求中 headers
- Re-deploy API
已解决:https://github.com/mscdex/busboy/issues/199#issuecomment-505239005
我在 node.js
中为 multipart-form-data 使用 express-fileupload然后仅在 AWS API 网关上配置设置
Select API => 设置 => 二进制媒体类型 =>
现在没有损坏 formdata 中的任何文件,一切正常。
使用 AWS 从服务器上传和检索图像 API Gateway Proxy+ 和 Lambda 通过 AWS 网关和 lambda 代理上传和检索图像以及管理二进制数据的代码示例+