如何嚴格判斷文件上傳類型?再不會你就out啦!
ead>theme: condensed-night-purple highlight: atom-one-dark
文件上傳是工作中常見的業務需求,很多情況下,我們需要限制文件的上傳類型,比如只能上傳圖片。通常我們是通過input
元素的accept
屬性來限制文件的類型:
js
<input id="file" type="file" accept="image/*" />
或者通過截取文件名後綴的方式來判斷:
js
const ext = file.name.substring(file.name.lastIndexOf('.') + 1);
這樣做看似沒有毛病,但如果把其他文件的後綴名改為圖片格式,就可以成功突破這個限制。以上兩種方式都不嚴謹,存在一定的安全隱患。那麼應該如何解決這個問題呢?
一、查看文件的頭信息
所有文件在計算機中都是以二進制形式進行存儲的,但二進制數據是不方便做判斷的,我們可以利用 vscode 插件hexdump for VSCode
以十六進制的形式查看二進制文件。安裝完成後,點擊右上角的小圖標,即可查看文件的十六進制信息:
那麼,我們分別查看一下jpg png gif
的十六進制頭信息:
多打開幾個文件試試,你會發現同一種類型的文件,他們的頭信息是完全相同的。接下來,我們就可以根據頭信息來判斷文件類型了。
二、根據頭信息判斷文件類型
1. 將文件轉為十六進制字符串
在獲取文件對象後,我們可以通過FileReader API
來讀取文件的內容,然後將結果轉為Unicode
編碼,再轉為十六進制,以下是我封裝的將文件轉為十六進制字符串的方法:
js
async blobToString(blob) {
return new Promise(resolve => {
const reader = new FileReader()
reader.onload = function() {
const res = reader.result
.split("") // 將讀取結果分割為數組
.map(v => v.charCodeAt()) // 轉為 Unicode 編碼
.map(v => v.toString(16).toUpperCase()) // 轉為十六進制,再轉大寫
.map(v => v.padStart(2, "0")) // 個位數補0
.join(" "); // 轉為字符串
resolve(res)
}
reader.readAsBinaryString(blob) // 將文件讀取為二進制字符串
})
}
2. 判斷文件類型
其實沒有必要將整個文件轉為十六進制,我們只需要截取文件的前幾個字節,然後將截取後的文件轉為十六進制,再進行比對就可以了:
js
// 判斷是否為 jpg 格式
async function isJpg(file) {
const res = await blobToString(file.slice(0, 3))
return res === 'FF D8 FF'
}
// 判斷是否為 png 格式
async function isPng(file) {
const res = await blobToString(file.slice(0, 4))
return res === '89 50 4E 47'
}
// 判斷是否為 gif 格式
async function isGif(file) {
const res = await blobToString(file.slice(0, 4))
return res === '47 49 46 38'
}
3. 完整代碼
```html
```
三、總結
通過文件頭信息,我們除了可以判斷文件的類型,還可以讀取文件相關的元信息,比如圖片的尺寸、位深度、色彩類型和壓縮算法等,只是這些信息所在的位置不一樣。
按照以上方式,大家同樣可以判斷其他格式的文件,常用文件的文件頭。如果你還嫌麻煩,可以使用現成的第三庫來實現這個功能,比如 file-type 這個庫,有興趣的同學可以試一試。
看完記得點個贊呦!萬事開頭難,聽説喜歡點讚的你在 2022 年將迎來一個開門紅!😉
往期精彩
- Vite 性能篇:掌握這些優化策略,一起縱享絲滑!
- Vite 配置篇:日常開發掌握這些配置就夠了!
- Vite 入門篇:學會它,一起提升開發幸福感!
- 還有人沒嘗過 Pinia 嗎,請收下這份食用指南!
- 10個常見的使用場景,助你從 Vue2 絲滑過渡到 Vue3 !
- 前端手寫功能第二彈,提升內力,等待下一次爆發!
- 效率提升之 —— 如何優雅的帶走上份工作的VSCode配置
- Vue組件遞歸——組件化開發的必備技能!
- 10個常用的JS工具庫,80%的項目都在用!
- 如何嚴格判斷文件上傳類型?再不會你就out啦!
- Element-UI 奇淫技巧第二彈!提升開發效率,延長摸魚時間~
- 原來虛擬列表如此簡單!萬萬沒想到
- 10個常見的前端手寫功能,你全都會嗎?
- 一款強大到沒朋友的圖片編輯插件,愛了愛了!
- 如何實現拖拽上傳、上傳進度條,以及取消上傳?
- Vue 1分鐘實現右鍵菜單,懶人的福音!
- Vue 如何快速實現頭像裁剪?方法比你想象的簡單
- 前端持久化之瀏覽器存儲技術(localStorage、sessionStorage 、session、cookies)