Force download for lesson materials (Content-Disposition: attachment)
Lesson files were served inline (no Content-Disposition) → browsers opened PDFs in a new tab instead of downloading; flaky across browsers/providers. Set Content-Disposition: attachment with the human-readable filename (RFC 5987 for Cyrillic) on upload. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+12
-1
@@ -17,10 +17,20 @@ export function getPublicUrl(key: string): string {
|
||||
return `${process.env.S3_ENDPOINT}/${BUCKET}/${key}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Заголовок Content-Disposition для принудительного скачивания с человеческим
|
||||
* именем. RFC 5987: ASCII-фолбэк + UTF-8 (кириллица percent-encoded).
|
||||
*/
|
||||
export function attachmentDisposition(filename: string): string {
|
||||
const ascii = filename.replace(/[^\x20-\x7E]/g, "_").replace(/["\\]/g, "'");
|
||||
return `attachment; filename="${ascii}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
||||
}
|
||||
|
||||
export async function uploadFile(
|
||||
key: string,
|
||||
body: Buffer | Uint8Array,
|
||||
contentType: string
|
||||
contentType: string,
|
||||
contentDisposition?: string
|
||||
): Promise<string> {
|
||||
await s3.send(
|
||||
new PutObjectCommand({
|
||||
@@ -28,6 +38,7 @@ export async function uploadFile(
|
||||
Key: key,
|
||||
Body: body,
|
||||
ContentType: contentType,
|
||||
...(contentDisposition ? { ContentDisposition: contentDisposition } : {}),
|
||||
})
|
||||
);
|
||||
return getPublicUrl(key);
|
||||
|
||||
Reference in New Issue
Block a user