跳到主要內容
← 回到學習

學習 · 後端與資料庫

application-octet-stream

目錄 · 6 個段落
  1. 01為什麼存在這個 type
  2. 02觸發下載的標準組合
  3. 03Content-Disposition 三種值
  4. 04Node.js / Next.js 範例
  5. 05前端觸發下載的 client-side 寫法
  6. 06該用 octet-stream 嗎?(SO 上的爭議)

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/jsontext 顯示
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...>
http

兩個 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
http

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);
});
javascript

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"',
    },
  });
}
typescript

前端觸發下載的 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);  // 釋放記憶體
}
typescript

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"
http

精確 type 的好處:

  • 行動裝置選擇對的 app 開啟(PDF reader / Excel / 等)
  • 防毒軟體分析時更準確
  • 開發者除錯時看 Network tab 一眼識別
參考
TCP 學習筆記:application/octet-stream(RioTian)

目錄