application-octet-stream
application/octet-stream Content-Type
TL;DR==Content-Type: application/octet-stream = 「未知二進位流」,瀏覽器看到就 觸發下載==(不直接展示)。常用於檔案下載 endpoint。要客製化檔名要配 Content-Disposition: attachment; filename="xxx"。
為什麼存在這個 type
瀏覽器收到 response 後,看 Content-Type 決定怎麼處理:
| Content-Type | 行為 |
|---|---|
text/html | 渲染成網頁 |
image/png image/jpeg image/webp | 嵌入展示 |
video/mp4 | 內嵌播放器 |
application/pdf | 內建 PDF viewer 顯示 |
application/json | text 顯示 |
application/octet-stream | 觸發下載(瀏覽器不認識) |
當伺服器要強制使用者下載而非展示 時(例如:文件下載按鈕、報表匯出),就回 application/octet-stream。
觸發下載的標準組合
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="report-2026.pdf"
Content-Length: 102400
<binary data...>
兩個 header 各司其職:
| Header | 角色 |
|---|---|
Content-Type: application/octet-stream | 告訴瀏覽器這是「不認識的二進位」 |
Content-Disposition: attachment; filename="..." | 指定下載檔名 |
只有 octet-stream 不夠如果只有 Content-Type 沒設 Content-Disposition,Chrome 會用 URL 末段當檔名(例如 download.bin 或 GET path 的最後一段)。要控制檔名必須加 attachment directive。
Content-Disposition 三種值
# 1. inline:預設,作為頁面一部分顯示(若 Content-Type 支援)
Content-Disposition: inline
# 2. attachment:強制下載
Content-Disposition: attachment
# 3. attachment + 檔名
Content-Disposition: attachment; filename="filename.jpg"
Content-Disposition: attachment; filename*=UTF-8''%E5%A0%B1%E5%91%8A.pdf
filename*=UTF-8''... 用於非 ASCII 檔名(中文、日文等),因為 HTTP header 標準上只支援 ASCII。
Node.js / Next.js 範例
Express
app.get('/download/report', (req, res) => {
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', 'attachment; filename="report.pdf"');
fs.createReadStream('/path/to/report.pdf').pipe(res);
});
Next.js API Route
// app/api/download/route.ts
export async function GET() {
const file = await readFile('/path/to/report.pdf');
return new Response(file, {
headers: {
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment; filename="report.pdf"',
},
});
}
前端觸發下載的 client-side 寫法
如果伺服器 沒回 Content-Disposition(只回 application/octet-stream),前端可以用 Blob + <a download> 觸發下載:
async function downloadFile(url: string, filename: string) {
const res = await fetch(url);
const blob = await res.blob();
const objectUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = objectUrl;
a.download = filename; // ⭐ 強制下載 + 指定檔名
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(objectUrl); // 釋放記憶體
}
a.download attribute 強制觸發下載,即便伺服器沒設 Content-Disposition。前端控檔名比依賴後端更彈性。
CORS 限制跨域下載要伺服器允許 CORS,否則 fetch() 會被擋。Firebase Storage 跨域下載踩坑見 CORS firebase。
該用 octet-stream 嗎?(SO 上的爭議)
Stack Overflow 高讚回答:如果你知道精確的 MIME type 就用精確的,只在「真的不知道是什麼」才用 octet-stream。
例如:
# ✅ 已知 PDF,用精確 type
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
# ⚠️ 通用做法,瀏覽器仍會下載但失去 type 資訊
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="report.pdf"
精確 type 的好處:
- 行動裝置選擇對的 app 開啟(PDF reader / Excel / 等)
- 防毒軟體分析時更準確
- 開發者除錯時看 Network tab 一眼識別
參考TCP 學習筆記:application/octet-stream(RioTian)