如何在.NET Core的AWS Lambda中生成正确的Multipart响应?
问题描述
已将现有.NET Core服务迁移至AWS Lambda,但无法在function.cs中生成正确的Multipart响应。原服务返回IActionResult,生成的多部分响应包含XML和Base64编码的HTML两部分,但Lambda中尝试多种返回类型后,当前仅返回{}。需要生成如下结构的Multipart响应:
--d3742228-85fc-4218-bf24-7e9dec746710 Content-Type: text/xml; charset=utf-8 Content-id: ACORD <?xml version="1.0" encoding="utf-8"?> <ACORD> <InsuranceSvcRs> <Status> <StatusCd>0</StatusCd> <StatusDesc>Success</StatusDesc> </Status> </InsuranceSvcRs> </ACORD> --d3742228-85fc-4218-bf24-7e9dec746710 Content-Type: application/html; charset=utf-8 Content-id: Inquiry.html Content-description: Response to View Inquiry PCFET0NUWVBFIEhUTUwgUFVCTElDICctLy9XM0MvL0RURC= --d3742228-85fc-4218-bf24-7e9dec746710--
现有function.cs代码片段:
public async Task<IActionResult> FunctionHandler(ApiGatewayRequest.Root input, ILambdaContext context) { IActionResult? ugResult = null; var result = controller.Post(apiGatewayRequest.body); //return multip-part response ugResult = result.GetAwaiter().GetResult(); return ugResult; }
原REST控制器Post方法及自定义XmlAndEncodedHtmlMultipartResult类逻辑已在提问中给出。
解决方案
Lambda执行环境与普通ASP.NET Core不同,IActionResult的ExecuteResultAsync依赖ASP.NET Core原生HttpContext,而Lambda中无此上下文,直接返回IActionResult会导致内容无法正确解析,最终返回空对象。需直接构建Multipart内容,返回适配API Gateway的响应结构。
实现步骤
- 构建Multipart内容:复用原有的多部分内容生成逻辑,但直接操作
MultipartContent对象,无需依赖IActionResult。 - 适配API Gateway响应格式:API Gateway要求Lambda返回包含状态码、响应头、Base64编码内容的结构,需自定义响应类或返回符合要求的匿名对象。
- 修改Handler返回类型:将
IActionResult替换为适配API Gateway的响应类型。
修改后的代码示例
1. 定义API Gateway响应类
public class ApiGatewayResponse { public int StatusCode { get; set; } public Dictionary<string, string> Headers { get; set; } = new(); public string Body { get; set; } = string.Empty; public bool IsBase64Encoded { get; set; } = true; }
2. 重构FunctionHandler逻辑
public async Task<ApiGatewayResponse> FunctionHandler(ApiGatewayRequest.Root input, ILambdaContext context) { // 调用业务逻辑获取XML和HTML原始内容 var acordXml = await _gateway.ProcessIncomingRequestAndReturnXMLString(modifiedRequest, logTimeStamp); string htmlResponse = _gateway.CreateHtmlString(modifiedRequest, logTimeStamp); // 构建Multipart内容 var multipartContent = new MultipartContent(XmlAndEncodedHtmlMultipartResult.Subtype); // 添加XML部分 var xmlContent = new StringContent(acordXml, Encoding.UTF8, "text/xml"); xmlContent.Headers.Add("Content-id", "ACORD"); multipartContent.Add(xmlContent); // 添加Base64编码的HTML部分 var htmlBytes = Encoding.UTF8.GetBytes(htmlResponse); var encodedHtml = Convert.ToBase64String(htmlBytes); var htmlContent = new StringContent(encodedHtml, Encoding.UTF8, "application/html"); htmlContent.Headers.Add("Content-id", "Inquiry.html"); htmlContent.Headers.Add("Content-description", "Response to View Inquiry"); multipartContent.Add(htmlContent); // 将Multipart内容转为字节数组 using var memoryStream = new MemoryStream(); await multipartContent.CopyToAsync(memoryStream); var contentBytes = memoryStream.ToArray(); // 返回适配API Gateway的响应 return new ApiGatewayResponse { StatusCode = 200, Headers = new Dictionary<string, string> { ["Content-Type"] = multipartContent.Headers.ContentType.ToString() }, Body = Convert.ToBase64String(contentBytes), IsBase64Encoded = true }; }
3. 可选:复用原自定义Result类
如果不想重复代码,可修改XmlAndEncodedHtmlMultipartResult类,添加获取MultipartContent的方法:
public class XmlAndEncodedHtmlMultipartResult : IActionResult { // 原有代码保持不变... // 添加获取构建好的MultipartContent的方法 public MultipartContent GetMultipartContent() { _multipartContent.Add(_xmlContent); if (_htmlContent != null) _multipartContent.Add(_htmlContent); return _multipartContent; } }
然后在Handler中复用:
public async Task<ApiGatewayResponse> FunctionHandler(ApiGatewayRequest.Root input, ILambdaContext context) { var actionResult = await controller.Post(input.body); var multipartResult = actionResult as XmlAndEncodedHtmlMultipartResult; if (multipartResult == null) { return new ApiGatewayResponse { StatusCode = 500 }; } var multipartContent = multipartResult.GetMultipartContent(); using var memoryStream = new MemoryStream(); await multipartContent.CopyToAsync(memoryStream); var contentBytes = memoryStream.ToArray(); return new ApiGatewayResponse { StatusCode = 200, Headers = new Dictionary<string, string> { ["Content-Type"] = multipartContent.Headers.ContentType.ToString() }, Body = Convert.ToBase64String(contentBytes), IsBase64Encoded = true }; }
内容的提问来源于stack exchange,提问作者WorkJ
相关产品推荐
相关产品推荐

