在 Go 语言中获取文件的 MIME 类型

苏见山
苏见山
发布时间:2026-08-25| 52人浏览过
原创

前言

文件上传、媒体处理这类场景里,很多问题都出在“只看后缀名”这一步:扩展名能改,但文件内容不会配合伪装。本文用 Go 标准库和一个常见第三方库两种方式,说明 MIME 类型该怎么取、各自读取多少字节,以及什么场景下该优先选哪一种。

展示文件后缀判断与文件头识别差异的暖色专栏插图
后缀名与真实类型不是一回事只看扩展名不可靠,真正有效的是基于文件头特征识别 MIME 类型。

文件上传、媒体处理和资源校验这类场景里,判断文件类型几乎是基础动作。但只看 .jpg、.png 这样的后缀名并不稳妥,因为扩展名可以随手改掉,真正有意义的是文件内容本身暴露出来的 MIME 类型。下面就用 Go 里最常见的两种做法拆开来看:先看标准库怎么实现,再看第三方库在识别信息上能补到什么程度。

为什么不能只看文件后缀

在日常开发中,很多人会先从文件名入手判断类型,比如上传图片时检查是不是 jpg、png。这种方式实现简单,但并不可靠。

原因很直接:文件后缀是可以修改的。一个恶意程序完全可以伪装成 .jpg 再上传,如果系统只认文件名,不认内容,就可能把不该接收的文件放进业务流程,进而带来安全隐患。

更稳妥的做法,是读取文件内容的前几个字节,通过文件头特征来判断它的真实类型。对应到程序里,通常就是获取文件的 MIME 类型。

用 Go 标准库获取 MIME 类型

Go 标准库已经提供了现成能力。在 net/http 包里,可以直接使用 http.DetectContentType 判断内容类型。

这个方法的关键点在于:不需要把整个文件都读完,一般取前 512 个字节就可以完成识别。因此它很适合放在上传校验、文件预检查这类场景里。

package main

import (
    "fmt"
    "net/http"
    "os"
)

func main() {
    fi, err := os.Open("/path/videos/pkch.mp4")
    if err != nil {
        panic(err)
    }

    // 只需要前 512 个字节就可以了
    buffer := make([]byte, 512)

    _, _ = fi.Read(buffer)

    contentType := http.DetectContentType(buffer)

    fmt.Println(contentType) // video/mp4
}

这段代码的处理流程很直接:

读取文件头

先通过 os.Open 打开文件,然后分配一个 512 字节的缓冲区。这里读取的不是完整文件,而是用于识别类型的前导内容。

调用识别函数

http.DetectContentType(buffer) 会根据这段字节数据返回 MIME 类型。示例里输出结果是 video/mp4。

展示 Go 标准库与 filetype 库差异的暖色专栏插图
两种实现的取舍点标准库适合基础校验,第三方库更适合需要扩展识别信息的场景。

适用场景

如果你的需求只是做基础类型判断,例如限制上传文件必须是图片、音频或视频,标准库通常已经够用。它没有额外依赖,接入成本也最低。

第三方库实现:filetype

如果你希望使用专门做文件类型识别的库,也可以考虑 github.com/h2non/filetype。它同样基于文件头判断类型,写法也比较直接。

package main

import (
    "fmt"
    "os"

    "github.com/h2non/filetype"
)

func main() {
    fi, err := os.Open("/path/videos/pkch.mp4")
    if err != nil {
        panic(err)
    }

    // We only have to pass the file header = first 261 bytes
    buffer := make([]byte, 261)

    _, _ = fi.Read(buffer)

    kind, _ := filetype.Match(buffer)
    if kind == filetype.Unknown {
        fmt.Println("Unknown file type")
        return
    }

    fmt.Println(kind.MIME.Value) // video/mp4
}

和标准库相比,这个库的示例中只读取了前 261 个字节,然后调用 filetype.Match(buffer) 进行匹配。

返回结果的处理方式

这里先判断 kind == filetype.Unknown,如果没有识别出来,就输出 Unknown file type 并返回。识别成功时,再通过 kind.MIME.Value 取到 MIME 字符串,例如 video/mp4。

适合什么情况

当你不只想拿到一个基础 MIME 值,还希望借助更专门的匹配逻辑做扩展识别时,第三方库会更方便一些。代价则是需要引入额外依赖,并在项目里维护它的版本。

标准库和第三方库怎么选

如果只是一般业务校验,优先用标准库往往更合适。原因很简单:调用少、依赖少、可维护性也更好。对于大多数上传接口、资源检查流程,http.DetectContentType 已经能满足需求。

如果项目本身对文件类型识别有更细的要求,或者你已经在使用相关生态库,那么再考虑接入 github.com/h2non/filetype 也不迟。

无论选哪种方案,核心原则都一样:不要只信后缀名,应该基于文件头判断真实内容类型。对 Go 项目来说,这也是实现成本和安全性之间比较平衡的一种做法。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。