我正在尝试制作日志记录中间件,它记录(请求、响应(在某些情况下是异常),当异常发生时,我想返回自定义响应。
当前,当出现异常时,我无法写入响应体。
我的代码:
public async Task InvokeAsync(HttpContext context)
{
try
{
context.Request.EnableBuffering();
using (var reader = new StreamReader(
context.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 1024,
leaveOpen: true))
{
strRequestBody = await reader.ReadToEndAsync();
context.Request.Body.Position = 0;
}
var originalResponseBody = context.Response.Body;
using var newResponseBody = new MemoryStream();
context.Response.Body = newResponseBody;
await _next(context);
if (context.Response.StatusCode != 200)
{
newResponseBody.Seek(0, SeekOrigin.Begin);
var jsonResponseBody = JObject.Parse(await new StreamReader(context.Response.Body).ReadToEndAsync());
newResponseBody.Seek(0, SeekOrigin.Begin);
await newResponseBody.CopyToAsync(originalResponseBody);
_logger.LogInformation(
"HTTP {method} {url} => responded {statusCode}\n" +
"(response code: {responseCode}, response message: {message})\n" +
"Request query string: {queryString} \n" +
"Request body: {requestBody}",
context.Request?.Method,
context.Request?.Path.Value,
context.Response?.StatusCode,
jsonResponseBody["code"].ToString(),
jsonResponseBody["message"].ToString(),
context.Request?.QueryString.Value,
strRequestBody);
}
else
{
_logger.LogInformation(
"HTTP {method} {url} => responded {statusCode} \n" +
"Request query string: {queryString} \n" +
"Request body: {requestBody}",
context.Request?.Method,
context.Request?.Path.Value,
context.Response?.StatusCode,
context.Request?.QueryString.Value,
strRequestBody);
}
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
string jsonResponse = JsonConvert.SerializeObject(
BaseResponse.Failed(500, "Somthing went wrong."));
await context.Response.WriteAsync(jsonResponse, Encoding.UTF8);
_logger.LogError(
"HTTP {method} {url} => responded {statusCode} \n" +
"Request query string: {queryString} \n" +
"Request body: {requestBody} \n" +
"Error: {error}",
context.Request?.Method,
context.Request?.Path.Value,
context.Response?.StatusCode,
context.Request?.QueryString.Value,
strRequestBody,
"Exception message: " + ex.Message + "\n" +
"Exception stacktrace: " + ex.StackTrace + "\n" +
"Inner exception message: " + ex.InnerException?.Message + "\n" +
"Inner exception stacktrace: " + ex.InnerException?.StackTrace);
}
}
在(catch)块中,这一行:
await context.Response.WriteAsync(jsonResponse, Encoding.UTF8);
抛出此异常:
System.ObjectDisposedException: Cannot access a closed Stream.
我的问题:在发生异常时,如何从中间件返回自定义响应?
提前谢谢,
发布于 2022-05-26 23:43:21
响应体是不可读的流,因此您需要将一个可读流分配给主体,以便读取它,如下行:
var originalResponseBody = context.Response.Body;
using var newResponseBody = new MemoryStream();
context.Response.Body = newResponseBody;
在MemoryStream等待_next(上下文)之前,我们将它分配给响应体。
当等待_next(上下文)被调用并且管道中发生异常时,执行转到(catch)块,这里我们需要将响应体还原回原来的流,然后在(catch)块(第一行)中写入它:
catch (Exception ex)
{
context.Response.Body = originalResponseBody;
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
string jsonResponse = JsonConvert.SerializeObject(
BaseResponse.Failed(500, "Somthing went wrong."));
await context.Response.WriteAsync(jsonResponse, Encoding.UTF8);
_logger.LogError(
"HTTP {method} {url} => responded {statusCode} \n" +
"Request query string: {queryString} \n" +
"Request body: {requestBody} \n" +
"Error: {error}",
context.Request?.Method,
context.Request?.Path.Value,
context.Response?.StatusCode,
context.Request?.QueryString.Value,
strRequestBody,
"Exception message: " + ex.Message + "\n" +
"Exception stacktrace: " + ex.StackTrace + "\n" +
"Inner exception message: " + ex.InnerException?.Message + "\n" +
"Inner exception stacktrace: " + ex.InnerException?.StackTrace);
}
https://stackoverflow.com/questions/72392385
复制相似问题