Content 檢測使用指南
Package:
io.leandev.appfuse.content.*狀態: 穩定
簡介
Content 模組提供智慧的檔案內容類型檢測工具,基於檔案內容而非檔名進行 MIME 類型識別,有效防止檔案偽裝攻擊。
核心特色
| 特色 | 說明 | 價值 |
|---|---|---|
| 多層檢測策略 | 平台檢測 → 魔術位元組 → 副檔名降級 | 準確率高、容錯性好 |
| 安全驗證 | 基於檔案內容而非檔名 | 防止檔案偽裝攻擊 |
| 跨平台相容 | 自動適配 Linux/macOS/Windows | 行為一致 |
| 豐富格式支援 | 70+ 種常見格式 | 開箱即用 |
與傳統做法的對比
// ❌ 傳統做法:依賴副檔名,容易被偽造
String filename = uploadedFile.getOriginalFilename();
String mimeType = filename.endsWith(".jpg") ? "image/jpeg" : "application/octet-stream";
// 風險:惡意使用者可上傳 virus.exe 並改名為 image.jpg
// ✅ AppFuse Content:多層檢測,安全可靠
ContentDetector detector = new ContentDetector();
MediaType type = detector.detect(uploadedFile.getInputStream());
// 即使檔名是 .jpg,內容是 .exe 也會被正確識別
快速開始
檢測檔案路徑
import io.leandev.appfuse.content.ContentDetector;
import org.springframework.http.MediaType;
ContentDetector detector = new ContentDetector();
Path imagePath = Paths.get("/upload/photo.jpg");
MediaType type = detector.detect(imagePath);
System.out.println(type); // image/jpeg
檢測上傳檔案(Spring MVC)
@PostMapping("/upload")
public ResponseEntity<String> handleUpload(@RequestParam("file") MultipartFile file)
throws IOException {
ContentDetector detector = new ContentDetector();
MediaType actualType = detector.detect(file.getInputStream());
// 驗證檔案類型
if (!actualType.isCompatibleWith(MediaType.IMAGE_JPEG)
&& !actualType.isCompatibleWith(MediaType.IMAGE_PNG)) {
return ResponseEntity.badRequest()
.body("Only JPEG and PNG images are allowed");
}
// 安全處理檔案...
return ResponseEntity.ok("Upload successful");
}
檢測位元組陣列
ContentDetector detector = new ContentDetector();
byte[] imageData = downloadFromUrl("https://example.com/image");
MediaType type = detector.detect(imageData);
if (type.getType().equals("image")) {
System.out.println("這是一張圖片:" + type.getSubtype());
}
支援的格式
圖片格式 (13 種)
JPEG, PNG, GIF, WebP, BMP, SVG, ICO, TIFF, AVIF, HEIC, HEIF
文檔格式 (7 種)
PDF, TXT, CSV, XML, JSON, Markdown
Office 格式 (6 種)
DOC, DOCX, XLS, XLSX, PPT, PPTX
壓縮格式 (5 種)
ZIP, GZIP, TAR, 7Z, RAR
網頁格式 (7 種)
HTML, CSS, JavaScript, TypeScript, JSX, TSX
程式碼格式 (10 種)
Java, Python, Go, Rust, C, C++, Shell, Bash
影音格式 (10 種)
MP4, AVI, MOV, WebM, MKV, MP3, WAV, OGG, FLAC, AAC
配置檔案 (5 種)
YAML, TOML, INI, Properties
常見場景
場景 1: 檔案上傳驗證
ContentDetector detector = new ContentDetector();
MediaType type = detector.detect(uploadedFile.getInputStream());
if (!type.getType().equals("image")) {
throw new InvalidFileException("Expected image file, but got: " + type);
}
場景 2: 安全檢查(防止檔案偽裝)
String filename = "document.pdf";
MediaType detectedType = detector.detect(fileBytes);
String expectedType = filename.substring(filename.lastIndexOf('.') + 1);
if (!detectedType.getSubtype().contains(expectedType)) {
logger.warn("File extension mismatch: {} vs {}", filename, detectedType);
// 拒絕可疑檔案或進一步驗證
}
場景 3: 檔案分類處理
ContentDetector detector = new ContentDetector();
MediaType type = detector.detect(filePath);
switch (type.getType()) {
case "image":
imageProcessor.process(filePath);
break;
case "video":
videoProcessor.process(filePath);
break;
case "application":
if (type.getSubtype().equals("pdf")) {
pdfProcessor.process(filePath);
}
break;
default:
genericProcessor.process(filePath);
}
場景 4: 動態設定 Content-Type
@GetMapping("/download/{fileId}")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileId) throws IOException {
File file = fileService.getFile(fileId);
Resource resource = new FileSystemResource(file);
ContentDetector detector = new ContentDetector();
MediaType mediaType = detector.detect(file.toPath());
return ResponseEntity.ok()
.contentType(mediaType)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getName() + "\"")
.body(resource);
}
檢測策略
Path 檢測策略
1. 平台原生檢測 (Files.probeContentType)
↓ 失敗
2. 副檔名映射查詢
↓ 失敗
3. 預設類型 (application/octet-stream)
InputStream 檢測策略
1. 魔術位元組分析 (URLConnection.guessContentTypeFromStream)
↓ 失敗
2. 預設類型 (application/octet-stream)
最佳實踐
✅ 推薦做法
// 1. 重複使用 detector 實例(無狀態,執行緒安全)
private final ContentDetector detector = new ContentDetector();
// 2. 優先使用串流檢測(更準確)
MediaType type = detector.detect(inputStream);
// 3. 結合檔案驗證
if (type.isCompatibleWith(MediaType.IMAGE_JPEG) ||
type.isCompatibleWith(MediaType.IMAGE_PNG)) {
// 處理圖片
}
❌ 避免的做法
// 1. 不要只依賴副檔名
String ext = filename.substring(filename.lastIndexOf('.'));
// ❌ 不安全,容易被偽造
// 2. 不要忽略檢測結果
detector.detect(file); // ❌ 沒有使用檢測結果
processFile(file);
常見問題
Q: 不同作業系統結果是否一致?
A: 大致一致,但因 Files.probeContentType() 實作不同,可能有細微差異。建議在 CI 環境中測試。
Q: 無法識別的檔案會怎樣?
A: 返回 application/octet-stream,不會拋出異常。
Q: 效能如何?
A: ContentDetector 內建常用 MIME 類型快取。建議重複使用實例、批次處理時可並行處理。
API 參考
詳細的類別設計和方法簽名,請參閱 API 參考: Content 或 Javadoc。