无法从部署在 Lambda 上的 asp.net 核心 api 上的 HttpContext 读取请求正文
Unable to read request body from HttpContext on asp.net core api deployed on Lambda
我有一个 asp.net 核心 wed api 当前托管在 IIS 上,我正在尝试将其迁移到 AWS Lambda。
为此 api 我编写了一个日志记录中间件,它记录所有传入的请求及其各自的响应。中间件的InvokeAsync方法代码如下(仅相关部分)
public async Task InvokeAsync(HttpContext context)
{
try
{
var request = context.Request;
var requestTime = DateTime.UtcNow;
var requestBodyContent = await ReadRequestBody(request);
var originalBodyStream = context.Response.Body;
using (var responseBody = new MemoryStream())
{
var response = context.Response;
//The context.Response.Body memory stream cannot be read from more than once. If we read it here to log it the response to the client will be empty
//Instead we have all subsequent middleware write to the temporary responseBody memory stream which we can later read from
response.Body = responseBody;
//calculate the duration of the call
Stopwatch callDurationTimer = new Stopwatch();
callDurationTimer.Start();
await next(context);
callDurationTimer.Stop();
string responseBodyContent = null;
responseBodyContent = await ReadResponseBody(response);
//we write the contents of the temporary response memory stream to the original response memory stream in order to return the correct response.
await responseBody.CopyToAsync(originalBodyStream);
/*
code that logs to a DB
*/
}
}
catch (Exception e)
{
logger.LogError(e, "Logging Middleware Error");
await next(context);
}
}
以及 ReadRequestBody 函数的代码
private async Task<string> ReadRequestBody(HttpRequest request)
{
request.EnableRewind();
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.Body.ReadAsync(buffer, 0, buffer.Length);
var bodyAsText = Encoding.UTF8.GetString(buffer);
request.Body.Seek(0, SeekOrigin.Begin);
bodyAsText = Regex.Replace(bodyAsText, @"\s+", "");
return bodyAsText;
}
以上代码在 IIS 托管方案中按预期工作。
在 Lambda 场景中,我遇到了以下问题:尝试读取请求正文没有任何结果。 ReadRequestBodyFunction 的结果是一个空字符串。其他一切正常。日志记录和系统的其余部分。
有人知道 Lambda 在将请求移交给我的 api 之前对请求做了什么,这使得请求正文不可读吗?
如果这很重要,我正在使用 asp.net 核心 2.2 并且该应用程序是独立的,因此它可以 运行 在仅支持 .net 核心 2.1 的 Lambda 上。
我通过查看 Amazon.Lambda.AspNetCoreServer 包代码 (v4.0.0) 找到了解决方案。
在某些时候,当他们编组请求时,他们将请求的主体设置为 MemoryStream。这似乎以某种方式混淆了 request.ContentLength
属性 在这行代码中始终为 null
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
request.Body.Length
属性 虽然按预期工作。所以将上面的行更改为
var buffer = new byte[Convert.ToInt32(request.Body.Length)];
解决了问题。
我有一个 asp.net 核心 wed api 当前托管在 IIS 上,我正在尝试将其迁移到 AWS Lambda。
为此 api 我编写了一个日志记录中间件,它记录所有传入的请求及其各自的响应。中间件的InvokeAsync方法代码如下(仅相关部分)
public async Task InvokeAsync(HttpContext context)
{
try
{
var request = context.Request;
var requestTime = DateTime.UtcNow;
var requestBodyContent = await ReadRequestBody(request);
var originalBodyStream = context.Response.Body;
using (var responseBody = new MemoryStream())
{
var response = context.Response;
//The context.Response.Body memory stream cannot be read from more than once. If we read it here to log it the response to the client will be empty
//Instead we have all subsequent middleware write to the temporary responseBody memory stream which we can later read from
response.Body = responseBody;
//calculate the duration of the call
Stopwatch callDurationTimer = new Stopwatch();
callDurationTimer.Start();
await next(context);
callDurationTimer.Stop();
string responseBodyContent = null;
responseBodyContent = await ReadResponseBody(response);
//we write the contents of the temporary response memory stream to the original response memory stream in order to return the correct response.
await responseBody.CopyToAsync(originalBodyStream);
/*
code that logs to a DB
*/
}
}
catch (Exception e)
{
logger.LogError(e, "Logging Middleware Error");
await next(context);
}
}
以及 ReadRequestBody 函数的代码
private async Task<string> ReadRequestBody(HttpRequest request)
{
request.EnableRewind();
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.Body.ReadAsync(buffer, 0, buffer.Length);
var bodyAsText = Encoding.UTF8.GetString(buffer);
request.Body.Seek(0, SeekOrigin.Begin);
bodyAsText = Regex.Replace(bodyAsText, @"\s+", "");
return bodyAsText;
}
以上代码在 IIS 托管方案中按预期工作。
在 Lambda 场景中,我遇到了以下问题:尝试读取请求正文没有任何结果。 ReadRequestBodyFunction 的结果是一个空字符串。其他一切正常。日志记录和系统的其余部分。
有人知道 Lambda 在将请求移交给我的 api 之前对请求做了什么,这使得请求正文不可读吗?
如果这很重要,我正在使用 asp.net 核心 2.2 并且该应用程序是独立的,因此它可以 运行 在仅支持 .net 核心 2.1 的 Lambda 上。
我通过查看 Amazon.Lambda.AspNetCoreServer 包代码 (v4.0.0) 找到了解决方案。
在某些时候,当他们编组请求时,他们将请求的主体设置为 MemoryStream。这似乎以某种方式混淆了 request.ContentLength
属性 在这行代码中始终为 null
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
request.Body.Length
属性 虽然按预期工作。所以将上面的行更改为
var buffer = new byte[Convert.ToInt32(request.Body.Length)];
解决了问题。