Handling File Downloads
1. Using Content-Disposition Header
| Header Value | Behavior |
|---|---|
inline | Display in browser if possible |
attachment | Force download dialog |
attachment; filename="report.pdf" | Suggested filename (ASCII) |
filename*=UTF-8''r%C3%A9sum%C3%A9.pdf | RFC 5987 Unicode filename |
2. Implementing Streaming Downloads
| Method | Notes |
|---|---|
| Chunked Transfer-Encoding | HTTP/1.1; no Content-Length needed |
| HTTP/2 streams | Native streaming |
| Backpressure | Pause read when client buffer full |
| Avoid loading full file in memory | Use file streams / S3 GetObject pipe |
3. Using Range Requests
Example: Range Request
GET /videos/large.mp4 HTTP/1.1
Range: bytes=1024-2047
HTTP/1.1 206 Partial Content
Content-Range: bytes 1024-2047/52428800
Content-Length: 1024
Accept-Ranges: bytes
Content-Type: video/mp4
<1024 bytes>
4. Implementing Resume Support
| Header | Purpose |
|---|---|
Accept-Ranges: bytes | Server advertises range support |
Range: bytes=N- | Resume from byte N |
If-Range: ETag | Resume only if file unchanged |
| 206 Partial Content | Successful range response |
5. Setting Content-Type Header
| File Type | MIME |
|---|---|
application/pdf | |
| JSON | application/json |
| CSV | text/csv |
| ZIP | application/zip |
| PNG / JPEG / WebP | image/png / image/jpeg / image/webp |
| MP4 / WebM | video/mp4 / video/webm |
| Unknown binary | application/octet-stream |
6. Generating Temporary Download URLs
| Tech | Lifetime |
|---|---|
| S3 presigned URL | 1s - 7d |
| Signed JWT in URL | Custom expiration |
| Signed cookies (CloudFront) | Cover multiple downloads from one session |
7. Implementing Download Authorization
| Pattern | Trade-off |
|---|---|
| API proxy + auth check | Full control, more bandwidth |
| Pre-signed URL after auth | Offload to CDN/storage |
| Token in query (short-lived) | Simple; logs may leak token |
8. Handling Download Errors
| Status | Cause |
|---|---|
| 404 | File not found |
| 410 | File expired/deleted |
| 416 Range Not Satisfiable | Range outside file |
| 403 | Permission denied |
9. Providing File Metadata
| Method | Purpose |
|---|---|
| HEAD request | Get size, type, last-modified without body |
| Sibling endpoint | GET /files/{id} returns metadata; /files/{id}/content returns bytes |
| Header echo | X-Filename, X-Checksum |
10. Implementing ZIP Archives
| Approach | Notes |
|---|---|
| Stream ZIP creation | archiver (Node), zip4j (Java) |
| Pre-generated ZIP | Cache for popular bundles |
| ZIP64 | Required for files > 4 GB or > 65k entries |
| Compression level | 0 (store) for already-compressed media |