Límites de tamaño de carga en ASP.NET Core: Kestrel, IIS y MVC
En ASP.NET Core, una foto grande puede rechazarse en seis lugares, y solo el último es tu código. Los demás responden a su manera: un 413 sin cuerpo, un 400 de ProblemDetails de MVC, una página de error de IIS o una conexión cortada que el navegador indica como error de red. Esta página enumera las capas en el orden en que las encuentra una solicitud, con lo que devolvió cada una cuando la probamos.
Las capas, en orden
- El editor. Con
maxUploadFileSize: 4000000en las opciones, la galería rechaza un archivo más grande antes de enviarlo. Un archivo de 4.5 MB dio "big.jpg is 4.3 MB. The maximum allowed size is 3.8 MB." El cuadro de diálogo cuenta en megabytes binarios. El servidor no puede depender de esto. - IIS, si la aplicación se ejecuta in-process detrás de él. Según la documentación de Microsoft, el filtrado de solicitudes rechaza los cuerpos que superan
maxAllowedContentLength(en bytes, 30,000,000 de forma predeterminada) con la página 404.13 propia de IIS, antes de que se ejecute ASP.NET Core. No probamos IIS para esta página. - El
MaxRequestBodySizede Kestrel, 30,000,000 bytes de forma predeterminada. Una carga de 31,000,000 bytes recibió un 413. - El límite propio de la ruta.
[RequestSizeLimit]sustituye el límite de Kestrel para una acción. En una Minimal API, el mismo atributo funciona como metadatos del endpoint. - El analizador multipart.
FormOptions.MultipartBodyLengthLimites de 134,217,728 bytes de forma predeterminada. Ajústalo por acción con[RequestFormLimits], o por endpoint con.WithFormOptions. - Tu comprobación: 4,000,000 bytes en el ejemplo, con una respuesta 413 en JSON.
El código
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;El límite de la solicitud es el límite del archivo más 64 KB para los delimitadores multipart y el campo folder. Ese margen es intencionado: un archivo que supera por poco los 4,000,000 bytes sigue llegando al código y recibe una respuesta legible.
// 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);Qué ve el navegador
Cuando una solicitud supera el límite de la ruta, Kestrel responde 413 y cierra la conexión mientras el navegador todavía está enviando. Enviamos 10 MB desde Chromium con un XHR, saltándonos la comprobación propia del editor, en los cuatro ejemplos de ASP.NET Core. Todas las veces el XHR terminó en onerror con estado 0, nunca con un 413. rte-files.js informa entonces "The server could not be reached." curl, que espera la respuesta, sí vio el 413. Así que el maxUploadFileSize del editor es lo que da a los usuarios un mensaje útil con los archivos grandes. Mantenlo igual que el límite del servidor.
MVC responde 400, no 413
En una Minimal API, un cuerpo que supera el límite de la ruta falla durante el enlace de parámetros, y el endpoint responde 413 con el cuerpo vacío. En un [ApiController] falla en cambio durante el enlace de modelos, y la validación automática del modelo responde con un 400 de ProblemDetails:
{"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."]}}Un archivo de 4,100,000 bytes dio la misma respuesta, porque con el formato multipart la solicitud superaba por poco los 4,065,536 bytes. El 413 {"error": ...} de la comprobación propia del ejemplo necesita que la solicitud completa quepa bajo el límite de la ruta, y un archivo de 4,050,000 bytes cabe.
Por encima de MultipartBodyLengthLimit, con el límite de la solicitud desactivado, un endpoint de Minimal API también respondió 400 (carga de 135,000,000 bytes frente a los 134,217,728 predeterminados).
Aumentar el límite
Cambia a la vez MaxFileBytes en RteFiles.cs y maxUploadFileSize en la página. MaxRequestBytes sigue a MaxFileBytes, así que el límite de la ruta y el límite multipart se mueven con él. Por encima de 30,000,000 bytes, todas las capas anteriores también deben permitirlo: el límite global de Kestrel se sigue aplicando a otras rutas, y la documentación de Microsoft dice que en IIS hay que aumentar maxAllowedContentLength en web.config, porque [RequestSizeLimit] no puede superarlo.
Pruébalo
Ejecuta el proyecto de ejemplo de esta guía con dotnet run (puerto 5302) y, a su lado, el ejemplo de Minimal API (puerto 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 413La primera respuesta es un 413 de la comprobación del ejemplo, en cualquiera de los dos puertos. La segunda es el 413 de Kestrel sin cuerpo. Envía huge.jpg al puerto 5302 para ver el 400 de MVC descrito arriba.
La misma guía para otras plataformas
JavaScript · Next.js · PHP · MVC 5 · Web Forms