做 Web 应用程序时,经常需要对用户上传的文件类型做一下检查,比如判断上传的是否是 png
、gif
、jpg
等图片类型,还是 pdf
。并针对不同的类型做一些处理,比如在需要图片的场合,如果上传的文件类型为非图片,那么就要拒绝并告诉用户需要一张图片。
这种需求,往往我们都是通过上传的文件的扩展名来判断,比如如果以 .jpg
结尾,那么我们可能就认为是 jpg
图片。
但这种判断方式往往存在一个隐患,就是恶意用户可能会把一些恶意程序简单的以 .jpg
结尾来骗过我们的逻辑。在这种情况下,最好的方式就是根据上传内容的前几个字节来判断。
根据上传的内容来判断上传的内容类型,一般情况前三个字节或者前八个自己就可以了。比如 PNG 格式的图片,以十六进制 89504E47
开头
http.DetectContentType() 方法
Go 语言的 net/http
包下的方法 http.DetectContentType()
就是使用了刚刚我们提到的前几个字节判断文件类型的方式。
http.DetectContentType()
方法会读取内容的前 512 个字节的内容,并根据它们判断文件的类型,然后返回该文件的 MIME 类型。如果是未知类型,则会返回 application/octet-stream
其实一般情况下用不了 512 个字节,顶多使用前 32 个字节。
我们写一个范例,使用 http.DetectContentType()
返回文件的 MINE 类型
package main import ( "os" "fmt" "net/http" ) func main() { // Open File f, err := os.Open("test.pdf") if err != nil { panic(err) } defer f.Close() // Get the content contentType, err := GetFileContentType(f) if err != nil { panic(err) } fmt.Println("Content Type: " + contentType) } func GetFileContentType(out *os.File) (string, error) { // 只需要前 512 个字节就可以了 buffer := make([]byte, 512) _, err := out.Read(buffer) if err != nil { return "", err } contentType := http.DetectContentType(buffer) return contentType, nil }
目前尚无回复