最直接方法是用 mime.typebyextension,但需先用 path.ext(path.base(filename)) 安全提取扩展名;它不读文件内容、仅查内置映射表,缺失类型需手动注册;无扩展名或需内容检测时应使用第三方库如 mimetype。

Go 如何根据文件扩展名获取 MIME 类型
用 mime.TypeByExtension 最直接,但它只查扩展名后缀,不读文件内容。比如 .jpg 返回 image/jpeg,.md 返回 text/x-markdown(如果注册过)。
常见错误是传入带路径的字符串,比如 /home/user/report.pdf —— 它会返回空字符串,因为函数只认 .pdf 这种纯后缀。得先用 path.Base 和 path.Ext 提取扩展名:
ext := path.Ext(path.Base(filename)) // 安全提取 .pdf、.tar.gz 等 mimeType := mime.TypeByExtension(ext)
注意:.tar.gz 这类双扩展名,path.Ext 返回 .gz,不是 .tar.gz;Go 标准库默认不支持多级扩展名映射,需要手动处理或改用第三方库。
为什么 mime.TypeByExtension 对某些后缀返回空
因为 Go 的 MIME 映射表是静态内置的,只包含常见后缀(如 .js、.css、.png),很多现代格式没注册,比如 .webp、.avif、.toml、.yaml 默认都查不到。
立即学习“go语言免费学习笔记(深入)”;
- 可通过
mime.AddExtensionType手动注册:mime.AddExtensionType(".webp", "image/webp") - 注册需在程序启动早期做(比如
init()函数里),否则并发调用时可能 panic - 标准库不会自动加载系统 MIME 数据库(如
/etc/mime.types),别指望它像 Python 的mimetypes.guess_type那样“智能”
想靠文件内容识别 MIME 类型怎么办
mime.TypeByExtension 不读文件,所以无法识别无扩展名、扩展名错误或伪造的文件。这时候得用 magic number(文件头字节)检测。
Go 标准库不提供此功能,必须借助第三方包,最常用的是 gabriel-vasile/mimetype:
import "github.com/gabriel-vasile/mimetype"<br>mt, _ := mimetype.DetectFile("/tmp/upload.bin")<br>fmt.Println(mt.String()) // e.g. "application/pdf"
它支持常见格式(PDF、ZIP、JPEG、ELF、SQLite 等),但要注意:
- 检测依赖前 512 字节,小文件要确保读全
- 比扩展名查表慢一个数量级,高并发场景慎用
- 不能替代校验(比如用户上传
.jpg但内容是 PHP 脚本,mimetype 只能告诉你“这不像图片”,不报错也不拦截)
Web 服务中设置响应头该用哪个 MIME 值
HTTP 响应中设 Content-Type,优先用扩展名查表 + 显式 fallback,而不是依赖文件内容检测。
原因很实际:
- 性能:查扩展名是 O(1),读文件头要 I/O 和计算
- 可控性:你明确知道用户上传的是
.csv,就该发text/csv,哪怕他偷偷改了文件头 - 浏览器兼容性:有些老客户端只看
Content-Type,不解析内容
典型写法:
ext := path.Ext(name)<br>if ext == "" { ext = ".bin" }<br>contentType := mime.TypeByExtension(ext)<br>if contentType == "" { contentType = "application/octet-stream" }<br>w.Header().Set("Content-Type", contentType)
别忘了加 fallback,否则遇到未知扩展名,contentType 是空字符串,直接塞进 header 会导致浏览器乱码或下载失败。










