我有一个网络应用,用户需要上传.zip文件。在服务器端,我正在检查上传文件的mime类型,以确保它是application/x-zip-compressed
或application/zip
。
这对我和Firefox和IE都很好。然而,当一个同事测试它时,它在Firefox上失败了(发送的mime类型类似于“application/octet-stream
”)但是在Internet Explorer上工作。我们的设置似乎是相同的:IE8,FF 3.5.1禁用所有附加组件,Win XP SP3,WinRAR作为本机.zip文件处理程序安装(不确定是否相关)。
所以我的问题是:浏览器如何确定要发送的mime类型?
请注意:我知道mime类型是由浏览器发送的,因此不可靠。我只是检查它是为了方便 - 主要是为了给出一个比你通过尝试打开非zip文件作为zip文件获得的更友好的错误消息,并避免加载(可能是沉重的)zip文件库。 的
答案 0 :(得分:57)
Chrome (撰写时的第38版)有3种方法可以确定MIME类型,并按特定顺序执行此操作。下面的代码段来自文件src/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=170(kPrimaryMappings
和kSecondaryMappings
)。
示例:从安装了Microsoft Excel的Windows系统上传CSV文件时,Chrome会将其报告为application/vnd.ms-excel
。这是因为在第一个硬编码列表中未指定.csv
,因此浏览器会回退到系统注册表。 HKEY_CLASSES_ROOT\.csv
的值为Content Type
,设置为application/vnd.ms-excel
。
再次使用相同的示例,浏览器将报告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行。您正在寻找defaultMimeEntries
和extraMimeEntries
。
使用我当前的个人资料,浏览器会报告text/csv
,因为mimeTypes.rdf
中有一个条目(上面列表中的第2项)。使用没有此条目的新配置文件,浏览器将报告application/vnd.ms-excel
(列表中的第3项)。
浏览器中的硬编码列表非常有限。通常,浏览器发送的MIME类型将是操作系统报告的类型。这就是为什么,如问题中所述,浏览器报告的MIME类型不可靠。
答案 1 :(得分:10)
Kip,我花了一些时间阅读RFC,MSDN和MDN。这是我能理解的。当浏览器遇到要上载的文件时,它会查看它接收的第一个数据缓冲区,然后对其进行测试。这些测试试图确定文件是否是已知的mime类型,如果已知mime类型,它将简单地进一步测试它的已知mime类型并相应地采取行动。我认为IE首先尝试这样做,而不仅仅是从扩展名中确定文件类型。此页面为IE http://msdn.microsoft.com/en-us/library/ms775147%28v=vs.85%29.aspx解释了这一点。对于firefox,我能理解的是它尝试从文件系统或目录条目中读取文件信息,然后确定文件类型。这是FF https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile的链接。我仍然希望有更多权威信息。
答案 2 :(得分:5)
这可能是操作系统,可能依赖浏览器,但在Windows上,可以通过查看HKCR下的注册表找到给定文件扩展名的MIME类型:
例如:
HKEY_CLASSES_ROOT.zip - ContentType
要从MIME扩展到文件,您可以查看
下的按键HKEY_CLASSES_ROOT \ Mime \ Database \ Content Type
获取特定MIME类型的默认扩展名。
答案 3 :(得分:5)
虽然这不是您问题的答案,但它确实解决了您要解决的问题。 YMMV。
正如您所写,mime类型不可靠,因为每个浏览器都有其确定方式。但是,浏览器会发送文件的原始名称(包括扩展名)。因此,解决问题的最佳方法是检查文件的扩展名而不是MIME类型。
如果你仍然需要mime类型,你可以使用你自己的apache的mime.types来确定它的服务器端。
答案 4 :(得分:0)
我同意johndodo,有很多变量使得从浏览器发送的mime类型不可靠。我会排除收到的子类型,只关注像'application'这样的类型。如果您的应用程序是基于PHP的,您可以使用函数explode()轻松完成此操作。 另外,只需检查文件扩展名以确保它是.zip或您正在寻找的任何其他压缩!
答案 5 :(得分:0)
根据rfc1867 - Form-based file upload in HTML:
如果是,每个部分都应标有适当的内容类型 媒体类型是已知的(例如,从文件扩展名或 操作系统输入信息)或作为application / octet-stream。
所以我的理解是,application/octet-stream
有点像blanket catch-all
标识符,如果类型不能推断。