浏览器如何确定上传文件的mime类型?


87

我有一个Web应用程序,用户需要在其中上传.zip文件。在服务器端,我正在检查上载文件的mime类型,以确保它是application/x-zip-compressedapplication/zip

这对我在Firefox和IE上运行正常。但是,当一个同事对其进行测试时,它在Firefox上对他失败(发送的MIME类型类似于“ application/octet-stream”),但在Internet Explorer上工作。我们的设置似乎是相同的:IE8,FF 3.5.1(禁用所有加载项),Win XP SP3,WinRAR作为本机.zip文件处理程序安装(不确定是否相关)。

所以我的问题是:浏览器如何确定要发送的哑剧类型?

请注意:我知道mime类型是由浏览器发送的,因此是不可靠的。我只是为了方便起见而检查它-主要是通过尝试将非zip文件作为zip文件打开,并避免加载(可能很重)zip文件库,从而给出比您得到的友好的错误消息。


application / octet-stream指定一个二进制文件。您应该能够获取文件的扩展名,以查看它是否为zip文件。只是为了澄清一下,这对FF有帮助吗,但对您没有帮助吗?
凯文·克罗威尔

是的,它在两种浏览器中都对我有效
Kip

看一看input/@formenctypeform/@enctype属性
tuxSlayer

Answers:


72

Chrome (撰写本文时为版本38)具有3种确定MIME类型的方式,并且以某种顺序进行。下面的代码片段来自filesrc/net/base/mime_util.cc方法MimeUtil::GetMimeTypeFromExtensionHelper

// We implement the same algorithm as Mozilla for mapping a file extension to
// a mime type.  That is, we first check a hard-coded list (that cannot be
// overridden), and then if not found there, we defer to the system registry.
// Finally, we scan a secondary hard-coded list to catch types that we can
// deduce but that we also want to allow the OS to override.

硬编码列表早于文件:https : //cs.chromium.org/chromium/src/net/base/mime_util.cc? l =170kPrimaryMappingskSecondaryMappings)。

例如:从装有Microsoft Excel的Windows系统上传CSV文件时,Chrome会将其报告为application/vnd.ms-excel。这是因为.csv未在第一个硬编码列表中指定,因此浏览器将退回到系统注册表。HKEY_CLASSES_ROOT\.csv有一个名为的值Content Type,设置为application/vnd.ms-excel

IE浏览器

再次使用相同的示例,浏览器将报告application/vnd.ms-excel。我认为假设Internet Explorer (撰写本文时为版本11)使用注册表是合理的。可能还使用了Chrome和Firefox等硬编码列表,但其封闭的源代码性质使其难以验证。

火狐浏览器

如Chrome代码所示,Firefox (撰写本文时为32版)的工作方式类似。文件片段uriloader\exthandler\nsExternalHelperAppService.cpp,方法nsExternalHelperAppService::GetTypeFromExtension

// OK. We want to try the following sources of mimetype information, in this order:
// 1. defaultMimeEntries array
// 2. User-set preferences (managed by the handler service)
// 3. OS-provided information
// 4. our "extras" array
// 5. Information from plugins
// 6. The "ext-to-type-mapping" category

硬编码列表位于文件中较早的位置,位于441行附近。您正在寻找defaultMimeEntriesextraMimeEntries

使用我当前的个人资料,浏览器将报告,text/csv因为在其中有一个条目mimeTypes.rdf(上面列表中的项目2)。使用没有该条目的新配置文件,浏览器将报告application/vnd.ms-excel(列表中的项目3)。

概要

浏览器中的硬编码列表非常有限。通常,浏览器发送的MIME类型将是操作系统报告的一种。正如问题中所指出的,这正是为什么浏览器报告的MIME类型不可靠的原因。


1
谢谢!在chrome源中是否有指向硬编码列表的链接?
2014年

@Kip是的,我添加了一个链接。Firefox似乎没有(官方)在线源代码浏览器,我不得不从其FTP服务器下载它。
user247702 2014年

将MIME作为ms-excel用于CSV令人讨厌,想知道为什么它不在硬编码列表中。
克里斯(Kris)


1
@VitalyIsaev粗略浏览了一下Chrome代码,表明该代码自2014
。– user247702

12

基普,我花了一些时间阅读RFC,MSDN和MDN。这是我能理解的。当浏览器遇到要上传的文件时,它会查看接收到的第一个数据缓冲区,然后对其进行测试。这些测试将尝试确定文件是否为已知的mime类型,如果已知的mime类型,它将简单地进一步测试该文件是否为已知的mime类型,并采取相应的措施。我认为IE会尝试首先执行此操作,而不仅仅是从扩展名中确定文件类型。此页面针对IE http://msdn.microsoft.com/zh-cn/library/ms775147%28v=vs.85%29.aspx对此进行了说明。对于firefox,我能理解的是它尝试从文件系统或目录条目中读取文件信息,然后确定文件类型。这是FF https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile的链接。我仍然想了解更多有关此的权威信息。


8

这可能取决于操作系统,可能取决于浏览器,但是在Windows上,可以通过在HKCR下的注册表中查找给定文件扩展名的MIME类型:

例如:

HKEY_CLASSES_ROOT.zip-ContentType

要从MIME转到文件扩展名,您可以查看下面的键

HKEY_CLASSES_ROOT \ Mime \ Database \ Content Type

获取特定MIME类型的默认扩展名。


谢谢。不幸的是,对于我和我的同事来说,这在我们的注册表中似乎都是正确的。我想这就是为什么它在IE中对他有效的原因,但是FF以某种方式获得了不同的效果……哦,好吧:(
Kip

5

尽管这不是您问题的答案,但确实可以解决您要解决的问题。YMMV。

如您所写,MIME类型是不可靠的,因为每种浏览器都有确定它的方式。但是,浏览器会发送文件的原始名称(包括扩展名)。因此,解决此问题的最佳方法是检查文件的扩展名而不是MIME类型。

如果仍然需要mime类型,则可以使用自己的apache的mime.types在服务器端确定它。


1
关心详细吗?以我的经验,浏览器总是发送正确的原始文件名(带有扩展名),而MIME类型却相差很大。所以是的,我要说它要可靠得多。
约翰多多

正确。我的意思是说,最终用户可以放置任何扩展名,而与实际类型无关,因此不应信任该扩展名。
Djizeus 2014年

没错,但是使用扩展名或MIME类型都没关系-永远不要信任用户提供的输入。但是OP明确表示他知道此问题,因此这不是此问题的一部分。顺便说一句,如果您删除了下降投票,我将不胜感激(我想它来自您)。
约翰多多

您是对的,没注意没问题,我不好。我可以取消投票,但您必须编辑答案(由系统强制执行)...
Djizeus 2014年

是的,我同意强多多的说法。正如Stijn在上面的回答中所述,Chrome和Firefox首先检查扩展程序。他们最终会做同样的事情。
詹妮克斯

0

我同意johndodo的观点,有太多的变量使从浏览器发送的mime类型变得不可靠。我会排除接收到的子类型,而只关注“应用程序”之类的类型。如果您的应用程序是基于php的,则可以使用explode()函数轻松地做到这一点。此外,只需检查文件扩展名以确保它是.zip或您正在寻找的其他任何压缩文件即可!


0

根据rfc1867-HTML中基于表单的文件上传

如果已知媒体类型(例如,从文件扩展名或操作系统键入信息推断出)或作为应用程序/八位字节流,则每个部分都应标记有适当的内容类型。

所以我的理解是,如果无法推断类型,application/octet-stream则有点像blanket catch-all标识符。


是的,我了解所有这些。问题是浏览器如何推断。
2015年

但这是值得知道的,对吧?如果application/octet-stream是万能的,那么另一种方法是信任浏览器(如果能够猜测的话),并在得到时进行自己的服务器端测试application/octet-stream
MikeBeaton '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.