在ASP.net Core中获取压缩的响应长度 [英] Get the compressed response length in ASP.net Core

查看:92
本文介绍了在ASP.net Core中获取压缩的响应长度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用在Kestrel上运行的.net Core构建了RESTful API.我刚刚使用"GzipCompressionProvider"中间件启用了压缩,如此处.

I've build a RESTful API using .net Core running on Kestrel. I've just enabled compression using "GzipCompressionProvider" middleware as described here.

我还使用了一个自定义记录器,该记录器将所有请求/响应记录到具有如下响应和请求长度的数据库中:

I'm also using a custom logger that logs all requests/responses to a DB with the response and request lengths as per below:

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中间件的实现如下:

The implementation of the Logger middleware is as follows:

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始终是预压缩长度.关于我需要更改的任何建议.我假设问题是仅在将响应刷新到客户端时才压缩响应?在那之后我可以添加我的记录器吗?

The trouble is that the ResponseLength is always the pre-compression length. Any suggestions on what I need to change. I'm assuming the issue is that the response is being compressed only when it is flushed to the client? Am I able to add my logger after that point?

推荐答案

问题在这里:

app.UseResponseCompression();
app.UseMiddleware<myMiddleware.LoggerMiddleware>();

按照该顺序,响应压缩中间件将被放置在中间件的前面.这意味着压缩中间件将在中间件之前得到请求,而处理响应在中间件之后之后.

With that order, the response compression middleware will be placed in front of your middleware. That means compression middleware will get request before your middleware, but process response after your middleware.

尝试在UseResponseCompression()之前添加中间件,您应该会看到压缩的内容.

Try to add your middleware before UseResponseCompression() and you should see compressed content.

参考: ASP.NET核心中间件管道

这篇关于在ASP.net Core中获取压缩的响应长度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆