Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Note
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.
Warning
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, przeczytaj artykuł w wersji .NET 9.
Rejestrowanie HTTP to oprogramowanie pośredniczące, które rejestruje informacje o przychodzących żądaniach HTTP i odpowiedziach HTTP. Rejestrowanie HTTP zapewnia dostęp do dzienników:
- Informacje o żądaniu HTTP
- Wspólne właściwości
- Headers
- Body
- Informacje o odpowiedzi HTTP
Rejestrowanie HTTP może:
- Rejestruj wszystkie żądania i odpowiedzi lub tylko żądania i odpowiedzi spełniające określone kryteria.
- Wybierz, które części żądania i odpowiedzi są rejestrowane.
- Umożliwia redagowania poufnych informacji z dzienników.
Rejestrowanie HTTP może zmniejszyć wydajność aplikacji, szczególnie podczas rejestrowania treści żądania i odpowiedzi. Podczas wybierania pól do rejestrowania należy wziąć pod uwagę wpływ na wydajność. Przetestuj wpływ wybranych ustawień logowania na wydajność.
Warning
Rejestrowanie HTTP może potencjalnie rejestrować dane osobowe . Rozważ ryzyko i unikaj rejestrowania poufnych informacji. Aby uzyskać więcej informacji na temat redagowania, sprawdź redagowanie poufnych danych
Włączanie rejestrowania HTTP
Rejestrowanie HTTP jest włączone przez wywołanie AddHttpLogging i UseHttpLogging, jak pokazano w poniższym przykładzie:
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();
Pusta lambda w poprzednim przykładzie wywołania AddHttpLogging dodaje oprogramowanie pośredniczące z konfiguracją domyślną. Domyślnie rejestrowanie HTTP rejestruje typowe właściwości, takie jak ścieżka, kod stanu i nagłówki dla żądań i odpowiedzi.
Dodaj następujący wiersz do appsettings.Development.json pliku na "LogLevel": { poziomie, aby wyświetlić dzienniki HTTP:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
W przypadku konfiguracji domyślnej żądanie i odpowiedź są rejestrowane jako para komunikatów podobnych do następującego przykładu:
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
Opcje rejestrowania HTTP
Aby skonfigurować globalne opcje oprogramowania pośredniczącego rejestrowania HTTP, wywołaj AddHttpLogging w Program.cs, używając wyrażenia lambda do skonfigurowania 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();
Note
W poprzednim przykładzie i poniższych przykładach UseHttpLogging jest wywoływana po UseStaticFiles, więc rejestrowanie HTTP nie jest włączone dla plików statycznych. Aby włączyć rejestrowanie HTTP pliku statycznego, wywołaj metodę UseHttpLogging przed UseStaticFiles.
LoggingFields
HttpLoggingOptions.LoggingFields to flaga wyliczenia, która konfiguruje określone części żądania i odpowiedzi na dziennik.
LoggingFields wartość domyślna to RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders i ResponseHeaders
RequestHeaders i ResponseHeaders to zestawy zarejestrowanych nagłówków HTTP. Wartości nagłówka są rejestrowane tylko dla nazw nagłówków, które znajdują się w tych kolekcjach. Poniższy kod dodaje sec-ch-ua do RequestHeaders, więc wartość nagłówka sec-ch-ua jest zapisywana. Dodaje MyResponseHeader do ResponseHeaders, co powoduje, że wartość nagłówka MyResponseHeader jest rejestrowana. Jeśli te wiersze zostaną usunięte, wartości tych nagłówków to [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 Udostępnia konfigurację do wybierania, które kodowanie ma być używane dla określonego typu nośnika.
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();
Takie podejście może również służyć do włączania rejestrowania danych, które nie są rejestrowane domyślnie (na przykład dane formularza, które mogą mieć typ nośnika, taki jak application/x-www-form-urlencoded lub multipart/form-data).
Metody MediaTypeOptions
RequestBodyLogLimit i 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
Ustawienie CombineLogs na true konfiguruje middleware, aby skonsolidować wszystkie aktywne dzienniki dla żądania i odpowiedzi w jeden dziennik na końcu. Obejmuje to żądanie, treść żądania, odpowiedź, treść odpowiedzi i czas trwania.
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();
Konfiguracja specyficzna dla punktu końcowego
W przypadku konfiguracji specyficznej dla punktu końcowego w minimalnych aplikacjach API dostępna jest metoda rozszerzenia. W poniższym przykładzie pokazano, jak skonfigurować rejestrowanie HTTP dla jednego punktu końcowego:
app.MapGet("/response", () => "Hello World! (logging response)")
.WithHttpLogging(HttpLoggingFields.ResponsePropertiesAndHeaders);
W przypadku konfiguracji specyficznej dla punktu końcowego w aplikacjach korzystających z kontrolerów [HttpLogging] atrybut jest dostępny. Atrybut może być również używany w minimalnych aplikacjach interfejsu API, jak pokazano w poniższym przykładzie:
app.MapGet("/duration", [HttpLogging(loggingFields: HttpLoggingFields.Duration)]
() => "Hello World! (logging duration)");
IHttpLoggingInterceptor
IHttpLoggingInterceptor to interfejs usługi, który można zaimplementować w celu obsługi wywołań zwrotnych dla poszczególnych żądań i odpowiedzi w celu dostosowania szczegółów, które są rejestrowane. Wszystkie ustawienia dziennika specyficzne dla punktu końcowego są stosowane najpierw, a następnie można je przesłonić w tych wywołaniach zwrotnych. Implementacja może:
- Sprawdź żądanie lub odpowiedź.
- Włącz lub wyłącz dowolny HttpLoggingFields.
- Dostosuj liczbę rejestrowanych treści żądania lub odpowiedzi.
- Dodaj pola niestandardowe do dzienników.
Zarejestruj implementację IHttpLoggingInterceptor , wywołując polecenie AddHttpLoggingInterceptor w pliku Program.cs. Jeśli zarejestrowano wiele IHttpLoggingInterceptor wystąpień, są one uruchamiane w kolejności zarejestrowanej.
W poniższym przykładzie pokazano, jak zarejestrować implementację IHttpLoggingInterceptor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.Duration;
});
builder.Services.AddHttpLoggingInterceptor<SampleHttpLoggingInterceptor>();
Poniższy przykład to implementacja IHttpLoggingInterceptor , która:
- Sprawdza metodę żądania i wyłącza rejestrowanie żądań POST.
- W przypadku żądań innych niż POST:
- Redaguje ścieżkę żądania, nagłówki żądania i nagłówki odpowiedzi.
- Dodaje niestandardowe pola i wartości pól do dzienników żądań i odpowiedzi.
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");
}
}
W przypadku tego przechwytywania żądanie POST nie generuje żadnych dzienników, nawet jeśli rejestrowanie HTTP jest skonfigurowane do rejestrowania HttpLoggingFields.All. Żądanie GET generuje dzienniki podobne do następującego przykładu:
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
Kolejność pierwszeństwa konfiguracji rejestrowania
Poniższa lista przedstawia kolejność pierwszeństwa konfiguracji rejestrowania:
- Konfiguracja globalna z HttpLoggingOptions, ustawiona przez wywołanie AddHttpLogging.
- Konfiguracja specyficzna dla punktu końcowego z atrybutu
[HttpLogging]lub WithHttpLogging metody rozszerzenia zastępuje konfigurację globalną. -
IHttpLoggingInterceptorjest wywoływany z wynikami i może dodatkowo modyfikować konfigurację dla każdego żądania.
Rejestrowanie HTTP to oprogramowanie pośredniczące, które rejestruje informacje o przychodzących żądaniach HTTP i odpowiedziach HTTP. Rejestrowanie HTTP zapewnia dostęp do dzienników:
- Informacje o żądaniu HTTP
- Wspólne właściwości
- Headers
- Body
- Informacje o odpowiedzi HTTP
Rejestrowanie HTTP jest przydatne w kilku scenariuszach:
- Rejestruj informacje o przychodzących żądaniach i odpowiedziach.
- Filtruj, które części żądania i odpowiedzi są rejestrowane.
- Filtrowanie nagłówków do zapisu w logach
Rejestrowanie HTTP może zmniejszyć wydajność aplikacji, szczególnie podczas rejestrowania treści żądania i odpowiedzi. Podczas wybierania pól do rejestrowania należy wziąć pod uwagę wpływ na wydajność. Przetestuj wpływ wybranych ustawień logowania na wydajność.
Warning
Rejestrowanie HTTP może potencjalnie rejestrować dane osobowe . Rozważ ryzyko i unikaj rejestrowania poufnych informacji.
Włączanie rejestrowania HTTP
Rejestrowanie HTTP jest włączone w programie UseHttpLogging, co dodaje oprogramowanie pośredniczące rejestrowania 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();
Domyślnie rejestrowanie HTTP rejestruje typowe właściwości, takie jak ścieżka, kod stanu i nagłówki dla żądań i odpowiedzi. Dodaj następujący wiersz do appsettings.Development.json pliku na "LogLevel": { poziomie, aby wyświetlić dzienniki HTTP:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
Dane wyjściowe są rejestrowane jako pojedynczy komunikat pod adresem LogLevel.Information.
Opcje rejestrowania HTTP
Aby skonfigurować middleware rejestrowania HTTP, wywołaj AddHttpLogging w 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();
Note
W poprzednim przykładzie i poniższych przykładach UseHttpLogging jest wywoływana po UseStaticFiles, więc rejestrowanie HTTP nie jest włączone dla pliku statycznego. Aby włączyć rejestrowanie HTTP pliku statycznego, wywołaj metodę UseHttpLogging przed UseStaticFiles.
LoggingFields
HttpLoggingOptions.LoggingFields to flaga wyliczenia, która konfiguruje określone części żądania i odpowiedzi na dziennik.
HttpLoggingOptions.LoggingFields wartość domyślna to RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
Headers to zestaw nagłówków żądań HTTP, które mogą być rejestrowane. Wartości nagłówka są rejestrowane tylko dla nazw nagłówków, które znajdują się w tej kolekcji. Poniższy kod rejestruje nagłówek żądania "sec-ch-ua". Jeśli logging.RequestHeaders.Add("sec-ch-ua"); zostanie usunięta, wartość nagłówka "sec-ch-ua" żądania zostanie zredagowana. Następujący wyróżniony kod wywołuje HttpLoggingOptions.RequestHeaders i 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 Udostępnia konfigurację do wybierania, które kodowanie ma być używane dla określonego typu nośnika.
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();
Takie podejście może również służyć do włączania rejestrowania danych, które nie są rejestrowane domyślnie. Na przykład, dane formularza mogą mieć taki typ nośnika, jak application/x-www-form-urlencoded lub multipart/form-data.
Metody MediaTypeOptions
RequestBodyLogLimit i 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();
Redagowanie poufnych danych
Rejestrowanie HTTP za pomocą funkcji redaction można włączyć, wywołując polecenie AddHttpLoggingRedaction:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.Duration;
});
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op => { });
Aby uzyskać więcej informacji na temat biblioteki zaciemniania danych platformy .NET, zobacz artykuł Zaciemnianie danych w .NET.
Opcje redakcji logów
Aby skonfigurować opcje rejestrowania z redakcją, wywołaj AddHttpLoggingRedaction w Program.cs za pomocą wyrażenia lambda do skonfigurowania LoggingRedactionOptions.
using Microsoft.Extensions.Compliance.Classification;
namespace HttpLoggingSample
{
public static class MyTaxonomyClassifications
{
public static string Name => "MyTaxonomy";
public static DataClassification Private => new(Name, nameof(Private));
public static DataClassification Public => new(Name, nameof(Public));
public static DataClassification Personal => new(Name, nameof(Personal));
}
}
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
W przypadku poprzedniej konfiguracji edycji, wynik jest podobny do następującego:
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[9]
Request and Response:
server.address: localhost:61361
Path: /
http.request.header.accept:
Protocol: HTTP/2
Method: GET
Scheme: https
http.response.header.content-type:
StatusCode: 200
Duration: 8.4684
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/2 GET https://localhost:61361/ - 200 - text/plain;+charset=utf-8 105.5334ms
Note
Ścieżka /home żądania nie jest rejestrowana, ponieważ jest uwzględniona w właściwości ExcludePathStartsWith.
http.request.header.accept i http.response.header.content-type zostały zredagowane przez Microsoft.Extensions.Compliance.Redaction.ErasingRedactor.
RequestPathLoggingMode
RequestPathLoggingMode określa, w jaki sposób ścieżka żądania jest rejestrowana, czy Formatted lub Structured, ustawiona przez IncomingPathLoggingMode:
-
Formatted: Rejestruje ścieżkę żądania bez parametrów. -
Structured: rejestruje ścieżkę żądania z dołączonymi parametrami.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
RequestPathParameterRedactionMode
RequestPathParameterRedactionMode określa, jak parametry trasy w ścieżce żądania powinny być ukryte, czy Strict, Loose, lub None, ustawione przez HttpRouteParameterRedactionMode:
-
Strict: Parametry trasy żądania są traktowane jako poufne, wymagają jawnej adnotacji z klasyfikacją danych i są domyślnie redagowane. -
Loose: Wszystkie parametry są traktowane jako niewrażliwe i domyślnie uwzględniane as-is. -
None: Parametry trasy nie są redagowane niezależnie od obecności adnotacji klasyfikacji danych.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
RequestHeadersDataClasses
RequestHeadersDataClasses mapuje nagłówki żądań na klasyfikację danych, która określa sposób ich redagowania:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
ResponseHeadersDataClasses
ResponseHeadersDataClasses, podobnie jak RequestHeadersDataClassesw przypadku nagłówków odpowiedzi:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
RouteParameterDataClasses
RouteParameterDataClasses mapuje parametry trasy do klasyfikacji danych:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
ExcludePathStartsWith
ExcludePathStartsWith określa ścieżki, które należy całkowicie wykluczyć z rejestrowania:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();
IncludeUnmatchedRoutes
IncludeUnmatchedRoutes umożliwia raportowanie niezgodnych tras. Jeśli ustawiono wartość true, loguje całą ścieżkę tras, które nie zostały zidentyfikowane przez Routing zamiast logować wartość Unknown dla atrybutu ścieżki:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");
app.Run();