Registro HTTP en ASP.NET Core
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión .NET 8 de este artículo.
Registro HTTP es un middleware que registra información sobre las solicitudes HTTP entrantes y las respuestas HTTP. El registro HTTP proporciona registros de:
- Información de solicitud HTTP
- Propiedades comunes
- Encabezados
- Cuerpo
- Información de respuesta HTTP
Registro HTTP:
- Registre todas las solicitudes y respuestas o solo solicitudes y respuestas que cumplan determinados criterios.
- Filtrar las partes de la solicitud y la respuesta que se registran.
- Permite censurar información confidencial de los registros.
Registro HTTP puede reducir el rendimiento de una aplicación, especialmente al registrar los cuerpos de solicitud y respuesta. Tenga en cuenta el impacto en el rendimiento al seleccionar los campos que se van a registrar. Pruebe cómo inciden en el rendimiento las propiedades de registro seleccionadas.
Advertencia
Registro HTTP puede registrar potencialmente información de identificación personal (PII). Tenga en cuenta el riesgo y evite registrar información confidencial.
Habilitación del registro HTTP
El registro HTTP está habilitado mediante una llamada a AddHttpLogging y UseHttpLogging, como se muestra en el ejemplo siguiente:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.Run();
La expresión lambda vacía del ejemplo anterior de llamada agrega AddHttpLogging
el middleware con la configuración predeterminada. De forma predeterminada, Registro HTTP registra propiedades comunes como ruta de acceso, código de estado y encabezados para solicitudes y respuestas.
Agregue la siguiente línea al archivo appsettings.Development.json
en el nivel "LogLevel": {
para que se muestren los registros HTTP:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
Con la configuración predeterminada, se registra una solicitud y una respuesta como un par de mensajes similares al ejemplo siguiente:
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
Request:
Protocol: HTTP/2
Method: GET
Scheme: https
PathBase:
Path: /
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Host: localhost:52941
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: [Redacted]
sec-ch-ua: [Redacted]
sec-ch-ua-mobile: [Redacted]
sec-ch-ua-platform: [Redacted]
sec-fetch-site: [Redacted]
sec-fetch-mode: [Redacted]
sec-fetch-user: [Redacted]
sec-fetch-dest: [Redacted]
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
StatusCode: 200
Content-Type: text/plain; charset=utf-8
Date: Tue, 24 Oct 2023 02:03:53 GMT
Server: Kestrel
Opciones de Registro HTTP
Para configurar las opciones globales para el middleware de registro HTTP, llame a AddHttpLogging en Program.cs
, mediante la expresión lambda para configurar HttpLoggingOptions.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Nota:
En el ejemplo anterior y los ejemplos siguientes, UseHttpLogging
se llama después de UseStaticFiles
, por lo que el registro HTTP no está habilitado para el archivo estático. Para habilitar el registro HTTP de archivos estáticos, llame a UseHttpLogging
antes de a UseStaticFiles
.
LoggingFields
HttpLoggingOptions.LoggingFields
es una marca de enumeración que configura partes específicas de la solicitud y respuesta para registrar. HttpLoggingOptions.LoggingFields
tiene RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders como valor predeterminado.
RequestHeaders
y ResponseHeaders
RequestHeaders y ResponseHeaders son conjuntos de encabezados HTTP que se registran. Los valores de encabezado solo se registran para los nombres de encabezado que están en esta colección. El código siguiente agrega sec-ch-ua
a RequestHeaders, por lo que se registra el valor del sec-ch-ua
encabezado. Y agrega MyResponseHeader
a ResponseHeaders, por lo que el valor del MyResponseHeader
encabezado se registra. Si se quitan estas líneas, los valores de estos encabezados son [Redacted]
.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
MediaTypeOptions
MediaTypeOptions proporciona la configuración para seleccionar la codificación que se va a usar para un tipo de medio específico.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Este enfoque también se puede usar para habilitar el registro de datos que no se registran de forma predeterminada (por ejemplo, datos de formulario, que pueden tener un tipo de medio como application/x-www-form-urlencoded
o multipart/form-data
).
Métodos de MediaTypeOptions
RequestBodyLogLimit
y ResponseBodyLogLimit
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
CombineLogs
Al establecer CombineLogs en true
se configura el middleware para consolidar todos sus registros habilitados para una solicitud y respuesta en un registro al final. Esto incluye la solicitud, el cuerpo de la solicitud, la respuesta, el cuerpo de la respuesta y la duración.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Configuración específica del punto de conexión
Para la configuración específica del punto de conexión en aplicaciones de API mínimas, hay disponible un WithHttpLogging método de extensión. En el ejemplo siguiente se muestra cómo configurar el registro HTTP para un punto de conexión:
app.MapGet("/response", () => "Hello World! (logging response)")
.WithHttpLogging(HttpLoggingFields.ResponsePropertiesAndHeaders);
Para la configuración específica del punto de conexión en aplicaciones que usan controladores, el [HttpLogging]
atributo está disponible. El atributo también se puede usar en aplicaciones de API mínimas, como se muestra en el ejemplo siguiente:
app.MapGet("/duration", [HttpLogging(loggingFields: HttpLoggingFields.Duration)]
() => "Hello World! (logging duration)");
IHttpLoggingInterceptor
IHttpLoggingInterceptor es la interfaz de un servicio que se puede implementar para controlar las devoluciones de llamada por solicitud y por respuesta para personalizar los detalles que se registran. Cualquier configuración de registro específica del punto de conexión se aplica primero y, a continuación, se puede invalidar en estas devoluciones de llamada. Una implementación puede:
- Inspeccione una solicitud o respuesta.
- Habilite o deshabilite cualquier HttpLoggingFields.
- Ajuste la cantidad del cuerpo de la solicitud o respuesta que se registra.
- Agregue campos personalizados a los registros.
Registre una IHttpLoggingInterceptor
implementación llamando a AddHttpLoggingInterceptor<T>
en Program.cs
. Si se registran varias IHttpLoggingInterceptor
instancias, se ejecutan en el orden registrado.
En el ejemplo siguiente se muestra cómo registrar una IHttpLoggingInterceptor
implementación:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.Duration;
});
builder.Services.AddHttpLoggingInterceptor<SampleHttpLoggingInterceptor>();
En el siguiente ejemplo se muestra una implementación de IHttpLoggingInterceptor
:
- Inspecciona el método de solicitud y deshabilita el registro de las solicitudes POST.
- Para solicitudes que no son POST:
- Redacta la ruta de acceso de solicitud, los encabezados de solicitud y los encabezados de respuesta.
- Agrega campos personalizados y valores de campo a los registros de solicitud y respuesta.
using Microsoft.AspNetCore.HttpLogging;
namespace HttpLoggingSample;
internal sealed class SampleHttpLoggingInterceptor : IHttpLoggingInterceptor
{
public ValueTask OnRequestAsync(HttpLoggingInterceptorContext logContext)
{
if (logContext.HttpContext.Request.Method == "POST")
{
// Don't log anything if the request is a POST.
logContext.LoggingFields = HttpLoggingFields.None;
}
// Don't enrich if we're not going to log any part of the request.
if (!logContext.IsAnyEnabled(HttpLoggingFields.Request))
{
return default;
}
if (logContext.TryDisable(HttpLoggingFields.RequestPath))
{
RedactPath(logContext);
}
if (logContext.TryDisable(HttpLoggingFields.RequestHeaders))
{
RedactRequestHeaders(logContext);
}
EnrichRequest(logContext);
return default;
}
public ValueTask OnResponseAsync(HttpLoggingInterceptorContext logContext)
{
// Don't enrich if we're not going to log any part of the response
if (!logContext.IsAnyEnabled(HttpLoggingFields.Response))
{
return default;
}
if (logContext.TryDisable(HttpLoggingFields.ResponseHeaders))
{
RedactResponseHeaders(logContext);
}
EnrichResponse(logContext);
return default;
}
private void RedactPath(HttpLoggingInterceptorContext logContext)
{
logContext.AddParameter(nameof(logContext.HttpContext.Request.Path), "RedactedPath");
}
private void RedactRequestHeaders(HttpLoggingInterceptorContext logContext)
{
foreach (var header in logContext.HttpContext.Request.Headers)
{
logContext.AddParameter(header.Key, "RedactedHeader");
}
}
private void EnrichRequest(HttpLoggingInterceptorContext logContext)
{
logContext.AddParameter("RequestEnrichment", "Stuff");
}
private void RedactResponseHeaders(HttpLoggingInterceptorContext logContext)
{
foreach (var header in logContext.HttpContext.Response.Headers)
{
logContext.AddParameter(header.Key, "RedactedHeader");
}
}
private void EnrichResponse(HttpLoggingInterceptorContext logContext)
{
logContext.AddParameter("ResponseEnrichment", "Stuff");
}
}
Con este interceptor, una solicitud POST no genera ningún registro aunque el registro HTTP esté configurado para registrar HttpLoggingFields.All
. Una solicitud GET genera registros similares al ejemplo siguiente:
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
Request:
Path: RedactedPath
Accept: RedactedHeader
Host: RedactedHeader
User-Agent: RedactedHeader
Accept-Encoding: RedactedHeader
Accept-Language: RedactedHeader
Upgrade-Insecure-Requests: RedactedHeader
sec-ch-ua: RedactedHeader
sec-ch-ua-mobile: RedactedHeader
sec-ch-ua-platform: RedactedHeader
sec-fetch-site: RedactedHeader
sec-fetch-mode: RedactedHeader
sec-fetch-user: RedactedHeader
sec-fetch-dest: RedactedHeader
RequestEnrichment: Stuff
Protocol: HTTP/2
Method: GET
Scheme: https
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
Content-Type: RedactedHeader
MyResponseHeader: RedactedHeader
ResponseEnrichment: Stuff
StatusCode: 200
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[4]
ResponseBody: Hello World!
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[8]
Duration: 2.2778ms
Orden de configuración de registro de prioridad
En la lista siguiente se muestra el orden de prioridad para la configuración de registro:
- Configuración global de HttpLoggingOptions, establecida llamando a AddHttpLogging.
- La configuración específica del punto de conexión del
[HttpLogging]
atributo o el método de WithHttpLogging extensión invalida la configuración global. IHttpLoggingInterceptor
se llama a con los resultados y puede modificar aún más la configuración por solicitud.
Registro HTTP es un middleware que registra información sobre las solicitudes HTTP entrantes y las respuestas HTTP. El registro HTTP proporciona registros de:
- Información de solicitud HTTP
- Propiedades comunes
- Encabezados
- Cuerpo
- Información de respuesta HTTP
Registro HTTP es útil en varios escenarios para:
- Registrar información sobre las solicitudes y respuestas entrantes.
- Filtrar las partes de la solicitud y la respuesta que se registran.
- Filtrar los encabezados que se registrarán.
El registro HTTP puede reducir el rendimiento de una aplicación, especialmente al registrar los cuerpos de solicitud y respuesta. Tenga en cuenta el impacto en el rendimiento al seleccionar los campos que se van a registrar. Pruebe cómo inciden en el rendimiento las propiedades de registro seleccionadas.
Advertencia
Registro HTTP puede registrar potencialmente información de identificación personal (PII). Tenga en cuenta el riesgo y evite registrar información confidencial.
Habilitación de Registro HTTP
Registro HTTP está habilitado con UseHttpLogging, que agrega middleware de registro HTTP.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.Run();
De forma predeterminada, Registro HTTP registra propiedades comunes como ruta de acceso, código de estado y encabezados para solicitudes y respuestas. Agregue la siguiente línea al archivo appsettings.Development.json
en el nivel "LogLevel": {
para que se muestren los registros HTTP:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
La salida se registra como un único mensaje en LogLevel.Information
.
Opciones de Registro HTTP
Para configurar el middleware de registro HTTP, llame a AddHttpLogging en Program.cs
.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Nota:
En el ejemplo anterior y los ejemplos siguientes, UseHttpLogging
se llama después de UseStaticFiles
, por lo que el registro HTTP no está habilitado para el archivo estático. Para habilitar el registro HTTP de archivos estáticos, llame a UseHttpLogging
antes de a UseStaticFiles
.
LoggingFields
HttpLoggingOptions.LoggingFields
es una marca de enumeración que configura partes específicas de la solicitud y respuesta para registrar. HttpLoggingOptions.LoggingFields
tiene RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders como valor predeterminado.
RequestHeaders
Headers son un conjunto de encabezados de solicitud HTTP que se pueden registrar. Los valores de encabezado solo se registran para los nombres de encabezado que están en esta colección. El código siguiente registra el encabezado de solicitud "sec-ch-ua"
. Si se quita logging.RequestHeaders.Add("sec-ch-ua");
, se redacta el valor del encabezado de solicitud "sec-ch-ua"
. El código resaltado siguiente llama a HttpLoggingOptions.RequestHeaders
y HttpLoggingOptions.ResponseHeaders
:
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
MediaTypeOptions
MediaTypeOptions proporciona la configuración para seleccionar la codificación que se va a usar para un tipo de medio específico.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Este enfoque también se puede usar para habilitar el registro de datos que no se registran de forma predeterminada. Por ejemplo, los datos de formulario, que podrían tener un tipo de medio como application/x-www-form-urlencoded
o multipart/form-data
.
Métodos de MediaTypeOptions
RequestBodyLogLimit
y ResponseBodyLogLimit
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();