asp.net - 获取 ASP.net Core 中的压缩响应长度
问题描述
我已经使用在 Kestrel 上运行的 .net Core 构建了一个 RESTful API。我刚刚使用“GzipCompressionProvider”中间件启用了压缩,如此处所述。
我还使用了一个自定义记录器,它将所有请求/响应记录到数据库中,响应和请求长度如下:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".apk"] = "application/vnd.android.package-archive";
app.UseCors("AllowAll");
app.UseResponseCompression();
app.UseMiddleware<myMiddleware.LoggerMiddleware>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Logger中间件的实现如下:
public LoggerMiddleware(RequestDelegate next, AuditContext dbcontext, IOptions<AppSettings> appsettings, IConfiguration config, ILoggerFactory loggerfactory)
{
_next = next;
dbContext = dbcontext;
appSettings = appsettings;
_config = config;
loggerFactory = loggerfactory;
}
public async Task Invoke(HttpContext context)
{
ApiLogEntry apiLog = null;
using (MemoryStream requestBodyStream = new MemoryStream())
{
using (MemoryStream responseBodyStream = new MemoryStream())
{
Stream originalRequestBody = context.Request.Body;
context.Request.EnableRewind();
Stream originalResponseBody = context.Response.Body;
try
{
await context.Request.Body.CopyToAsync(requestBodyStream);
requestBodyStream.Seek(0, SeekOrigin.Begin);
string requestBodyText = new StreamReader(requestBodyStream).ReadToEnd();
requestBodyStream.Seek(0, SeekOrigin.Begin);
context.Request.Body = requestBodyStream;
string responseBody = "";
context.Response.Body = responseBodyStream;
Stopwatch watch = Stopwatch.StartNew();
await _next(context);
watch.Stop();
responseBodyStream.Seek(0, SeekOrigin.Begin);
responseBody = new StreamReader(responseBodyStream).ReadToEnd();
string appName = "Tracy";
if (context.Request.Headers["tracy-app"] != "")
{
appName = context.Request.Headers["tracy-app"];
}
string token = "";
var authorization = context.Request.Headers["Authorization"].ToString();
if (authorization == "" || !authorization.Contains("Bearer"))
{
} else
{
token = authorization.Remove(0, 7).Trim();
}
string requestHeaders = string.Join(",", context.Request.Headers.Select(he => he.Key + ":[" + he.Value + "]").ToList());
string responseHeaders = string.Join(",", context.Response.Headers.Select(he => he.Key + ":[" + he.Value + "]").ToList());
apiLog = new ApiLogEntry
{
Application = appName,
Machine = Environment.MachineName,
RequestContentType = context.Request.ContentType,
RequestRouteTemplate = context.Request.Path,
RequestRouteData = requestBodyText,
RequestIpAddress = context.Connection.RemoteIpAddress.MapToIPv4().ToString(),
RequestMethod = context.Request.Method,
RequestHeaders = requestHeaders,
RequestTimestamp = DateTime.Now,
RequestUri = (context.Request.IsHttps ? "https://" : "http://") + context.Request.HttpContext.Request.Host.Value + context.Request.Path,
ResponseContentType = context.Response.ContentType,
ResponseHeaders = responseHeaders,
ResponseStatusCode = context.Response.StatusCode,
RequestLength = requestBodyText.Length + requestHeaders.Length,
ResponseLength = responseBody.Length + responseHeaders.Length,
Duration = watch.ElapsedMilliseconds,
SimId = context.Request.Headers["sim-serialnumber"],
DeviceId = context.Request.Headers["tracy-deviceid"],
ClientAppVersion = context.Request.Headers["app-version"],
UserId = dws.tracy.Security.AuthHelpers.GetUserId(appSettings, token)
};
if (appSettings.Value.Logging.LogResponse)
{
apiLog.ResponseContentBody = responseBody;
}
responseBodyStream.Seek(0, SeekOrigin.Begin);
await responseBodyStream.CopyToAsync(originalResponseBody);
if (apiLog != null && appSettings.Value.Logging.IsActive)
{
var apilogDB = Mapper.Map<dws.Data.ApiLogEntry>(apiLog);
using (var logContext = new AuditContext(_config.GetConnectionString("DwsContext")))
{
var apiLogRepo = new dws.Data.Repositories.ApiLogEntryRepository(logContext);
apiLogRepo.Add(apilogDB);
apiLogRepo.Commit();
}
}
}
catch (Exception ex)
{
//ExceptionLogger.LogToDatabse(ex);
string innerException = "";
if (ex.InnerException!=null)
{
innerException = ex.InnerException.Message;
}
ILogger logger;
logger = loggerFactory.CreateLogger("LoggerEntry");
logger.LogCritical(ex.ToString());
logger.LogCritical(innerException);
byte[] data = System.Text.Encoding.UTF8.GetBytes("Server error");
context.Response.StatusCode = 500;
originalResponseBody.Write(data, 0, data.Length);
}
finally
{
context.Request.Body = originalRequestBody;
context.Response.Body = originalResponseBody;
}
}
}
}
问题是 ResponseLength 始终是预压缩长度。关于我需要更改的任何建议。我假设问题是响应仅在刷新到客户端时才被压缩?在那之后我可以添加我的记录器吗?
解决方案
问题在这里:
app.UseResponseCompression();
app.UseMiddleware<myMiddleware.LoggerMiddleware>();
使用该顺序,响应压缩中间件将被放置在您的中间件之前。这意味着压缩中间件将在您的中间件之前获得请求,但在您的中间件之后处理响应。
尝试在之前添加中间件UseResponseCompression()
,您应该会看到压缩内容。
推荐阅读
- java - Cytoscape java:将边缘一直绘制到节点的中心
- c# - c# asp.net 身份和自定义角色
- yii2 - 如何更改 yii2 Query Builder 的数据库名称
- java - 休眠@ManyToOne 映射
- git - Git 提交速度非常慢
- node.js - 'await' 在等待基于 promise 的函数时对此表达式的类型没有影响
- tsql - 将 FIRST_VALUE 与基于另一列的条件一起使用
- typescript - Typescript fluent api builder多个参数(覆盖)不可能
- r - 如何下载和阅读htm。R中的文件
- c# - C# 在循环中显示另一个表单