Größenlimits für Uploads in ASP.NET Core: Kestrel, IIS und MVC
Ein großes Foto kann in ASP.NET Core an sechs Stellen abgewiesen werden, und nur die letzte davon ist Ihr Code. Die anderen antworten auf ihre eigene Weise: ein 413 ohne Body, ein ProblemDetails-400 von MVC, eine IIS-Fehlerseite oder eine abgebrochene Verbindung, die der Browser als Netzwerkfehler meldet. Diese Seite führt die Ebenen in der Reihenfolge auf, in der ein Request auf sie trifft, und nennt, was jede in unserem Test zurückgesendet hat.
Die Ebenen, der Reihe nach
- Der Editor. Mit
maxUploadFileSize: 4000000in den Optionen lehnt die Galerie eine größere Datei ab, bevor sie sie sendet. Eine Datei mit 4.5 MB ergab „big.jpg is 4.3 MB. The maximum allowed size is 3.8 MB.“ Der Dialog rechnet in binären Megabytes. Der Server kann sich nicht darauf verlassen. - IIS, wenn die App In-Process dahinter läuft. Laut Microsoft-Dokumentation lehnt die Anforderungsfilterung Bodys über
maxAllowedContentLength(in Bytes, standardmäßig 30,000,000) mit der eigenen IIS-Seite 404.13 ab, bevor ASP.NET Core läuft. IIS haben wir für diese Seite nicht getestet. MaxRequestBodySizevon Kestrel, standardmäßig 30,000,000 Bytes. Ein Upload mit 31,000,000 Bytes erhielt ein 413.- Das eigene Limit der Route.
[RequestSizeLimit]ersetzt das Limit von Kestrel für eine Action. In einer Minimal API funktioniert dasselbe Attribut als Endpoint-Metadaten. - Der Multipart-Parser.
FormOptions.MultipartBodyLengthLimitist standardmäßig 134,217,728 Bytes. Setzen Sie es pro Action mit[RequestFormLimits]oder pro Endpoint mit.WithFormOptions. - Ihre Prüfung: im Beispiel 4,000,000 Bytes, beantwortet mit einem JSON-413.
Der Code
public const long MaxFileBytes = 4_000_000;
// The request is a little bigger than the file: multipart boundaries, headers, the "folder" field.
public const long MaxRequestBytes = MaxFileBytes + 64 * 1024;Das Request-Limit ist das Dateilimit plus 64 KB für die Multipart-Grenzen und das Feld folder. Dieser Abstand ist Absicht: Eine Datei knapp über 4,000,000 Bytes erreicht so noch den Code und erhält eine lesbare Antwort.
// POST /rte/upload file, folder
[HttpPost("upload")]
[RequestSizeLimit(RteFiles.MaxRequestBytes)] // the whole request body
[RequestFormLimits(MultipartBodyLengthLimit = RteFiles.MaxRequestBytes)] // the multipart parser
public async Task<IActionResult> Upload(IFormFile? file, [FromForm] string? folder) =>
Send(await RteFiles.Save(HttpContext, file, folder));rte.MapPost("/upload", async (HttpContext http, IFormFile? file, [FromForm] string? folder) =>
Json(await RteFiles.Save(http, file, folder)))
.DisableAntiforgery()
// Kestrel accepts 30,000,000-byte bodies by default; this route needs ~4 MB.
.WithMetadata(new RequestSizeLimitAttribute(RteFiles.MaxRequestBytes))
.WithFormOptions(multipartBodyLengthLimit: RteFiles.MaxRequestBytes);Was der Browser sieht
Ist ein Request größer als das Limit der Route, antwortet Kestrel mit 413 und schließt die Verbindung, während der Browser noch sendet. Wir haben in allen vier ASP.NET-Core-Beispielen 10 MB aus Chromium per XHR gesendet und dabei die eigene Prüfung des Editors umgangen. Jedes Mal endete der XHR in onerror mit Status 0, nie mit einem 413. rte-files.js meldet dann „The server could not be reached.“ curl, das auf die Antwort wartet, sah das 413 dagegen. Für große Dateien gibt den Benutzern also maxUploadFileSize im Editor eine brauchbare Meldung. Halten Sie den Wert gleich dem Limit des Servers.
MVC antwortet mit 400, nicht mit 413
In einer Minimal API schlägt ein Body über dem Limit der Route bei der Parameterbindung fehl, und der Endpoint antwortet mit 413 und leerem Body. In einem [ApiController] schlägt er stattdessen bei der Modellbindung fehl, und die automatische Modellvalidierung antwortet mit einem ProblemDetails-400:
{"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more validation errors occurred.","status":400,
"errors":{"":["Failed to read the request form. Request body too large. The max request body size is 4065536 bytes."]}}Eine Datei mit 4,100,000 Bytes ergab dieselbe Antwort, weil der Request mit dem Multipart-Rahmen knapp über 4,065,536 Bytes lag. Das 413 mit {"error": ...} aus der eigenen Prüfung des Beispiels setzt voraus, dass der gesamte Request unter das Limit der Route passt, was bei einer Datei mit 4,050,000 Bytes der Fall ist.
Über MultipartBodyLengthLimit, bei ausgeschaltetem Request-Limit, antwortete ein Minimal-API-Endpoint ebenfalls mit 400 (Upload mit 135,000,000 Bytes gegen den Standardwert 134,217,728).
Das Limit erhöhen
Ändern Sie MaxFileBytes in RteFiles.cs und maxUploadFileSize auf der Seite gemeinsam. MaxRequestBytes folgt MaxFileBytes, sodass sich das Limit der Route und das Multipart-Limit mitbewegen. Über 30,000,000 Bytes muss auch jede vorgelagerte Ebene das zulassen: Das globale Limit von Kestrel gilt weiterhin für andere Routen, und laut Microsoft-Dokumentation muss bei IIS maxAllowedContentLength in web.config erhöht werden, weil [RequestSizeLimit] nicht darüber hinausgehen kann.
Testen
Starten Sie das Beispielprojekt zu dieser Anleitung mit dotnet run (Port 5302) und daneben das Minimal-API-Beispiel (Port 5301):
head -c 4050000 /dev/zero > big.jpg
curl -F "file=@big.jpg" http://localhost:5302/rte/upload
{"error":"The image is larger than 4 MB."}
head -c 10000000 /dev/zero > huge.jpg
curl -s -w "\nHTTP %{http_code}\n" -F "file=@huge.jpg" http://localhost:5301/rte/upload
HTTP 413Die erste Antwort ist ein 413 aus der Prüfung des Beispiels, auf beiden Ports. Die zweite ist das 413 von Kestrel ohne Body. Senden Sie huge.jpg an Port 5302, um das 400 von MVC von oben zu sehen.
Dieselbe Anleitung für andere Plattformen
JavaScript · Next.js · PHP · MVC 5 · Web Forms