Ведение журнала HTTP в ASP.NET Core
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Ведение журнала HTTP — это ПО промежуточного слоя, которое регистрирует сведения о входящих HTTP-запросах и ответах HTTP. Ведение журнала HTTP предоставляет журналы со следующими сведениями:
- HTTP-запросы;
- Общие свойства
- Заголовки
- Текст
- HTTP-ответы.
Ведение журнала HTTP может:
- Регистрируют все запросы и ответы или только запросы и ответы, соответствующие определенным критериям.
- Выберите, какие части запроса и ответа регистрируются.
- Разрешите отредактировать конфиденциальную информацию из журналов.
Ведение журнала HTTP может снизить производительность приложения, особенно при ведении журналов запросов и ответов. При выборе регистрируемых полей учитывайте возможное влияние на производительность. Проверьте влияние выбранных свойств ведения журнала на производительность.
Предупреждение
Ведение журнала HTTP может потенциально ведения журнала личных сведений (PII). Примите во внимание возможные риски и не записывайте конфиденциальную информацию.
Включение ведения журнала HTTP
Ведение журнала HTTP включено путем вызова AddHttpLogging и UseHttpLogging, как показано в следующем примере:
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();
Пустая лямбда в предыдущем примере вызова AddHttpLogging
добавляет ПО промежуточного слоя с конфигурацией по умолчанию. По умолчанию протоколирование HTTP регистрирует общие свойства, такие как путь, код состояния и заголовки для запросов и ответов.
Добавьте следующую строку в файл appsettings.Development.json
на уровне "LogLevel": {
, чтобы отображались журналы HTTP:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
При настройке по умолчанию запрос и ответ регистрируются как пара сообщений, аналогичных следующему примеру:
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
Параметры ведения журнала HTTP
Чтобы настроить глобальные параметры ПО промежуточного слоя ведения журнала HTTP, вызовите AddHttpLogging его Program.cs
, используя лямбда-файл для настройки 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();
Примечание.
В предыдущем примере и следующих примерах UseHttpLogging
вызывается после UseStaticFiles
этого, поэтому ведение журнала HTTP не включено для статических файлов. Чтобы включить ведение журнала HTTP статического файла, вызовите перед UseStaticFiles
вызовомUseHttpLogging
.
LoggingFields
HttpLoggingOptions.LoggingFields
— это флаг перечисления, который позволяет настроить определенные регистрируемые части запроса и ответа. HttpLoggingOptions.LoggingFields
по умолчанию использует RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
и ResponseHeaders
.
RequestHeaders и ResponseHeaders представляют собой наборы заголовков HTTP, которые регистрируются. Значения заголовков регистрируются только для имен заголовков, которые находятся в этих коллекциях. Следующий код добавляется sec-ch-ua
в RequestHeadersжурнал, поэтому значение заголовка sec-ch-ua
регистрируется. И он добавляется MyResponseHeader
в ResponseHeadersжурнал, поэтому значение заголовка MyResponseHeader
регистрируется. Если эти строки удалены, значения этих заголовков являются [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 предоставляет конфигурацию для выбора кодировки, используемой для конкретного типа носителя.
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();
Этот подход также можно использовать для включения ведения журнала для данных, которые не регистрируются по умолчанию (например, данные формы, которые могут иметь тип носителя, application/x-www-form-urlencoded
например или multipart/form-data
).
Методы MediaTypeOptions
RequestBodyLogLimit
и 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
Параметр CombineLogs настройки true
ПО промежуточного слоя для консолидации всех включенных журналов запроса и ответа в один журнал в конце. К ним относятся запрос, текст запроса, ответ, текст ответа и длительность.
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();
Конфигурация для конкретной конечной точки
Для конфигурации для конкретной конечной точки в минимальных приложениях WithHttpLogging API доступен метод расширения. В следующем примере показано, как настроить ведение журнала HTTP для одной конечной точки:
app.MapGet("/response", () => "Hello World! (logging response)")
.WithHttpLogging(HttpLoggingFields.ResponsePropertiesAndHeaders);
Для конфигурации для конкретной конечной точки в приложениях, использующих контроллеры, [HttpLogging]
атрибут доступен. Атрибут также можно использовать в минимальных приложениях API, как показано в следующем примере:
app.MapGet("/duration", [HttpLogging(loggingFields: HttpLoggingFields.Duration)]
() => "Hello World! (logging duration)");
IHttpLoggingInterceptor
IHttpLoggingInterceptor — это интерфейс для службы, которая может быть реализована для обработки запросов и обратных вызовов для каждого ответа для настройки сведений, которые регистрируются в журнале. Все параметры журнала, относящиеся к конечной точке, применяются сначала и затем можно переопределить в этих обратных вызовах. Реализация может:
- Проверьте запрос или ответ.
- Включите или отключите любой HttpLoggingFields.
- Измените объем регистра запроса или ответа.
- Добавьте настраиваемые поля в журналы.
IHttpLoggingInterceptor
Регистрация реализации путем вызова AddHttpLoggingInterceptor<T>
Program.cs
. Если зарегистрировано несколько IHttpLoggingInterceptor
экземпляров, они выполняются в порядке, зарегистрированном.
В следующем примере показано, как зарегистрировать реализацию IHttpLoggingInterceptor
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.Duration;
});
builder.Services.AddHttpLoggingInterceptor<SampleHttpLoggingInterceptor>();
В следующем примере показана IHttpLoggingInterceptor
реализация:
- Проверяет метод запроса и отключает ведение журнала для запросов POST.
- Для запросов, отличных от POST:
- Редактирует путь запроса, заголовки запросов и заголовки ответа.
- Добавляет настраиваемые поля и значения полей в журналы запросов и ответов.
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");
}
}
При использовании этого перехватчика запрос POST не создает журналы, даже если для журнала HTTP настроено ведение журнала HttpLoggingFields.All
. Запрос GET создает журналы, аналогичные следующему примеру:
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
Порядок настройки ведения журнала приоритета
В следующем списке показано порядок приоритета для конфигурации ведения журнала:
- Глобальная конфигурация из HttpLoggingOptions, заданная путем вызова AddHttpLogging.
- Конфигурация для конкретной конечной точки из атрибута
[HttpLogging]
или WithHttpLogging метода расширения переопределяет глобальную конфигурацию. IHttpLoggingInterceptor
вызывается с результатами и может дополнительно изменять конфигурацию для каждого запроса.
Ведение журнала HTTP реализуется с помощью ПО промежуточного слоя, которое регистрирует сведения о входящих HTTP-запросах и ответах. Ведение журнала HTTP предоставляет журналы со следующими сведениями:
- HTTP-запросы;
- Общие свойства
- Заголовки
- Текст
- HTTP-ответы.
Ведение журнала HTTP можно использовать в нескольких сценариях:
- запись сведений о входящих запросах и ответах;
- фильтрация регистрируемых частей запросов и ответов;
- фильтрация регистрируемых заголовков.
Ведение журнала HTTP может снизить производительность приложения, особенно при записи текста запроса и ответа. При выборе регистрируемых полей учитывайте возможное влияние на производительность. Проверьте влияние выбранных свойств ведения журнала на производительность.
Предупреждение
В ходе ведения журнала HTTP могут записываться личные сведения. Примите во внимание возможные риски и не записывайте конфиденциальную информацию.
Включение ведения журнала HTTP
Ведение журнала HTTP включается с использованием UseHttpLogging для добавления соответствующего ПО промежуточного слоя.
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();
По умолчанию в ходе ведения журнала HTTP в журнал записываются общие свойства, такие как путь, код состояния и заголовки для запросов и ответов. Добавьте следующую строку в файл appsettings.Development.json
на уровне "LogLevel": {
, чтобы отображались журналы HTTP:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
Выходные данные записываются в журнал как одно сообщение в LogLevel.Information
.
Параметры ведения журнала HTTP
Чтобы настроить ПО промежуточного слоя для ведения журнала HTTP, вызовите AddHttpLogging в 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();
Примечание.
В предыдущем примере и следующих примерах UseHttpLogging
вызывается после UseStaticFiles
этого, поэтому ведение журнала HTTP не включено для статического файла. Чтобы включить ведение журнала HTTP статического файла, вызовите перед UseStaticFiles
вызовомUseHttpLogging
.
LoggingFields
HttpLoggingOptions.LoggingFields
— это флаг перечисления, который позволяет настроить определенные регистрируемые части запроса и ответа. HttpLoggingOptions.LoggingFields
по умолчанию использует RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
Headers — это набор заголовков HTTP-запросов, которые разрешено регистрировать. Значения заголовков регистрируются только для имен заголовков в этой коллекции. Следующий код регистрирует заголовок "sec-ch-ua"
запроса. Если удалить logging.RequestHeaders.Add("sec-ch-ua");
, значение заголовка запроса "sec-ch-ua"
исключается из записи. Следующий выделенный код вызывает HttpLoggingOptions.RequestHeaders
и 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 предоставляет конфигурацию для выбора кодировки, используемой для конкретного типа носителя.
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();
Этот подход также можно использовать для включения ведения журнала для данных, которые не регистрируются по умолчанию. Например, данные формы, которые могут иметь тип носителя, например application/x-www-form-urlencoded
или multipart/form-data
.
Методы MediaTypeOptions
RequestBodyLogLimit
и 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();
ASP.NET Core