Lập trình · 25/09/2026

Content-Disposition: Tải file đúng tên và đúng cách

Một endpoint trả đúng dữ liệu PDF nhưng trình duyệt lại mở tài liệu thay vì tải xuống, hoặc lưu file với tên khó hiểu. Đây không nhất thiết là lỗi tạo PDF. Cách mô tả phản hồi HTTP cũng ảnh hưởng đến trải nghiệm nhận file.

Content-Disposition: Tải file đúng tên và đúng cách

Một endpoint trả đúng dữ liệu PDF nhưng trình duyệt lại mở tài liệu thay vì tải xuống, hoặc lưu file với tên khó hiểu. Đây không nhất thiết là lỗi tạo PDF. Cách mô tả phản hồi HTTP cũng ảnh hưởng đến trải nghiệm nhận file.

1. Tách loại nội dung khỏi cách xử lý

Content-Type mô tả kiểu dữ liệu, còn Content-Disposition gợi ý cách xử lý và tên file khi lưu. Ví dụ header cho một tài liệu giả định:

Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"

attachment hướng đến tải về; inline hướng đến xử lý theo kiểu nội dung, chẳng hạn hiển thị bằng trình xem PDF nếu client hỗ trợ. Không nên hứa rằng mọi trình duyệt luôn mở cùng một hộp thoại: thiết lập người dùng và khả năng client vẫn ảnh hưởng đến kết quả.

2. Tên lưu file không phải đường dẫn máy chủ

URL có thể là /documents/42/download trong khi tên gợi ý là report.pdf. Không cần để lộ thư mục lưu trữ nội bộ để người dùng nhận tên dễ đọc.

RFC 6266 xem tên do server cung cấp là thông tin gợi ý. Client cần xử lý an toàn trước khi lưu, đặc biệt với thành phần đường dẫn, ký tự điều khiển hoặc tên đặc biệt. Ở phía server, nên tạo tên tải về từ dữ liệu đã kiểm soát, không ghép nguyên đầu vào người dùng vào header.

3. Tên có dấu và phương án dự phòng

Có thể gửi một tên ASCII dự phòng qua filename và tên UTF-8 qua filename*. Ví dụ cho tên “báo cáo.pdf”:

Content-Disposition: attachment; filename="bao-cao.pdf"; filename*=UTF-8''b%C3%A1o%20c%C3%A1o.pdf

Client hiểu cả hai tham số sẽ ưu tiên filename*. Phần sau UTF-8'' là tên được mã hóa theo cú pháp tham số mở rộng, không phải yêu cầu đổi toàn bộ URL tải file. Tránh tự chắp nối thủ công trong ứng dụng thật; dùng API phản hồi tải file của framework và kiểm tra header được tạo.

Tên đẹp không bảo đảm nội dung đúng. Nếu server trả trang lỗi HTML nhưng gắn tên report.pdf, người dùng vẫn nhận file không mở được như PDF. Kiểm tra cả status, kiểu nội dung và dữ liệu thực tế.

4. Quyền tải là một lớp riêng

attachment không phải cơ chế phân quyền và không mã hóa tài liệu. Endpoint vẫn phải kiểm tra người yêu cầu có quyền với chính tài liệu đó. Một mã tài liệu khó đoán cũng không thay thế được kiểm tra quyền.

Với dữ liệu riêng tư, rà soát chính sách cache, log và cách chia sẻ URL. Không đưa bí mật vào tên file chỉ để người dùng dễ phân biệt. Header này cũng không quyết định file đã tải sẽ được quản lý ra sao trên thiết bị người nhận.

5. Kiểm tra theo đường tải thực tế

  1. Dùng tài liệu mẫu không nhạy cảm trong môi trường kiểm thử.
  2. Mở Network trong DevTools và xem phản hồi cuối chứa file, không chỉ phản hồi chuyển hướng.
  3. Kiểm tra status, Content-Type, Content-Disposition và tên đề xuất khi lưu.
  4. Thử tên ASCII, tên có dấu và tên có khoảng trắng trên các client cần hỗ trợ.
  5. Mở file bằng ứng dụng phù hợp để xác nhận nội dung không bị thay bằng trang lỗi.

Nếu frontend dùng JavaScript lấy dữ liệu rồi tự tạo file tải xuống, hãy kiểm tra riêng phần đặt tên phía frontend. Header từ server không có nghĩa mọi đoạn mã phía client đều tự sử dụng nó. Luồng mở URL trực tiếp và luồng JavaScript có thể cần các bài kiểm thử khác nhau.

6. Checklist bàn giao

  • Tên tải xuống dễ hiểu, không chứa đường dẫn nội bộ.
  • MIME phù hợp với dữ liệu thực.
  • Tên UTF-8 có phương án dự phòng và đã kiểm tra client.
  • Quyền truy cập được kiểm tra trước khi gửi tài liệu.
  • Phản hồi lỗi không bị đóng gói thành file thành công.

Một chức năng tải file hoàn chỉnh cần đồng thời đúng nội dung, đúng quyền và đúng trải nghiệm nhận file. Content-Disposition giải quyết một phần quan trọng của trải nghiệm đó, nhưng không thay thế các phần còn lại.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.