When building web applications that accept file uploads, handling oversized uploads gracefully becomes critical. While most developers know about the max-request-size
configuration, the default behavior of returning a static error page often doesn't meet modern UX requirements.
Since you're using Nginx as a front-end, we can leverage its powerful rewrite capabilities to implement this properly:
# nginx.conf
http {
client_max_body_size 10m; # Set your desired limit
server {
error_page 413 /custom_413.html;
location = /custom_413.html {
root /var/www/error_pages;
internal;
}
location /upload {
if ($request_method = POST) {
# Additional validation if needed
}
proxy_pass http://backend;
}
}
}
For more sophisticated handling, you can use Nginx's rewrite module:
map $content_length $upload_too_large {
default 0;
"~^[1-9][0-9]{7,}$" 1; # Matches content-length over 10MB
}
server {
if ($upload_too_large) {
rewrite ^ /file-too-big last;
}
location /file-too-big {
# Your custom error handling logic
return 413;
}
}
For complete control, combine Nginx with backend validation:
// Express.js middleware example
app.post('/upload', (req, res, next) => {
const contentLength = req.headers['content-length'];
if (contentLength > MAX_UPLOAD_SIZE) {
return res.redirect('/file-too-big');
}
next();
});
- Set appropriate
client_max_body_size
in both Nginx and your backend server - Handle chunked uploads differently as they won't have Content-Length header
- Consider using JavaScript validation before upload begins
- Provide clear error messages about size limits
When dealing with file uploads in web applications, we often need to enforce size limits. The standard approach of returning a generic 413 error page is insufficient for modern UX requirements. Here's how to implement custom redirection when uploads exceed specified limits.
The most efficient solution involves Nginx's client_max_body_size
directive combined with error page handling. Here's a production-tested configuration:
http {
# Set maximum body size (e.g., 10MB)
client_max_body_size 10m;
# Custom error handling
error_page 413 /upload_too_large.html;
server {
listen 80;
server_name example.com;
location /upload {
# Process uploads normally if within size limit
proxy_pass http://backend;
# Custom error handling for this specific location
error_page 413 /custom_upload_error;
}
location = /custom_upload_error {
internal;
return 302 /file_too_large?size=$request_length;
}
}
}
For more granular control, we can implement size checking before the upload begins:
// Client-side JavaScript example
document.getElementById('uploadForm').addEventListener('submit', function(e) {
const fileInput = document.getElementById('fileInput');
const maxSize = 10 * 1024 * 1024; // 10MB
if (fileInput.files[0].size > maxSize) {
e.preventDefault();
window.location.href = '/file_too_large?size=' + fileInput.files[0].size;
}
});
Even with frontend checks, always validate server-side. Here's a Node.js example:
app.post('/upload', (req, res, next) => {
const contentLength = parseInt(req.headers['content-length']);
const maxSize = 10 * 1024 * 1024; // 10MB
if (contentLength > maxSize) {
return res.redirect('/file_too_large?size=' + contentLength);
}
// Continue with normal upload processing
// ...
});
The complete flow should handle cases where the client doesn't cooperate with pre-validation:
- Client-side pre-check (JavaScript)
- Nginx size limitation
- Application-level validation
- Custom error page with helpful information
- Set reasonable timeout values (
client_body_timeout
) - Log large file attempts for security monitoring
- Provide clear error messages with size limits
- Consider implementing progressive uploads for better UX