为啥某些无效的 MIME 类型会触发“TypeError”,而其他无效的 MIME 类型会绕过错误并触发自动下载?

Posted

技术标签:

【中文标题】为啥某些无效的 MIME 类型会触发“TypeError”,而其他无效的 MIME 类型会绕过错误并触发自动下载?【英文标题】:Why do some invalid MIME types trigger a "TypeError," and other invalid MIME types bypass the error and trigger an unprompted download?为什么某些无效的 MIME 类型会触发“TypeError”,而其他无效的 MIME 类型会绕过错误并触发自动下载? 【发布时间】:2017-10-12 10:04:10 【问题描述】:

我正在制作一个相当简单的 Express 应用程序,其中只有几条路线。我的问题不是关于应用程序的功能,而是关于 Express 路线的一些奇怪行为。

当我启动服务器并使用 /search/* 路由或任何接受参数的路由时,我将这四种内容类型之一应用于响应:

res.setHeader('content-type', 'plain/text'); res.setHeader('content-type', 'plain/html'); res.setHeader('content-type', 'html/plain'); res.setHeader('content-type', 'html/text');

参数作为文件下载,没有任何提示。因此,使用search/foobar 会下载一个名为“foobar”的文件,该文件大小为 6 个字节,文件类型不受支持。现在我知道这四种类型都不是真正的 MIME 类型,我应该使用text/plaintext/html,但为什么要下载?这两种 MIME 类型的行为应有尽有,以下具有类型但没有子类型的 MIME 类型都按应有的方式失败,它们都返回 TypeError: invalid media type 错误:

res.setHeader('content-type', 'text'); res.setHeader('content-type', 'plain'); res.setHeader('content-type', 'html');

为什么某些无效类型会触发错误,而其他无效类型会绕过错误并触发下载?

到目前为止我发现了什么:

我在 Express 4.x 文档中发现 res.download(path [, filename]) 将路径中的文件作为“附件”传输,并且通常会提示用户下载,但此下载既不是提示也不是有意的。

我无法在 Express 文档(或此处在 SO)中找到任何类似的情况,即运行路线会导致文件自动下载到您的计算机。

起初我以为res.send(typeof(res)); 行导致下载,但在一次注释掉一行并重新运行服务器后,我发现只有当内容类型设置为'plain/text'下载是否发生。 res.send()里面的内容无关紧要,当content-type为plain/text时,/search/后面的文本会下载到我的机器上。

重新排列路径达到了相同的结果(除了下载之外,一切都正常运行。)

应用程序只是挂在/search/foo 之前到达的任何路径,但下载仍然通过。

我的代码:

'use strict';
var express = require('express');
var path = require('path');

var app = express();

app.get('/', function (req, res) 
  res.sendFile(path.join(__dirname+'/index.html'));
);


app.get('/search', function(req,res)
  res.send('search route');
);
app.get('/search/*', function(req, res, next) 
  res.setHeader('content-type', 'plain/text');
  var type = typeof(res);
  var reqParams = req.params;
  res.send(type);
);


var server = app.listen(process.env.PORT || 3000, function()
  console.log('app listening on port ' + process.env.PORT + '!');
);

module.exports = server;

其他详情

Express 版本 4.15.2 节点版本 4.7.3 使用 Cloud9 是快递新手 我的仓库是here,在“so_question”分支下

【问题讨论】:

【参考方案1】:

为什么有些无效类型会触发错误...

因为 MIME 类型具有它应该遵守的格式(记录在 RFC 2045 中),而触发错误的格式与该格式不匹配。

格式如下:

type "/" subtype *(";" parameter)

所以有一个强制类型、一个强制斜杠、一个强制子类型和以分号为前缀的可选参数。

但是,当 MIME 类型与该格式匹配时,它仅在语法上有效,不一定在语义上有效,这将我们带到您问题的第二部分:

...和其他无效类型绕过错误并触发下载?

接下来是RFC 2049:

在遇到任何无法识别的 Content-Type 字段时,实现必须将其视为媒体类型为“application/octet-stream”且没有参数子参数。如何处理此类数据取决于实现,但处理此类无法识别的数据的可能选项包括让用户将其写入文件(从其邮件传输格式解码)或为用户提供姓名应将解码数据作为输入传递给的程序。

(强调我的)

【讨论】:

就是这样!我在正在阅读的文档中注意到“应用程序/八位字节流”,并认为正在对返回的类型进行某种猜测,但这是我缺少的部分。非常感谢。【参考方案2】:

在 express 中定义路由的顺序很重要,您可能需要将默认的“/”路由移动到“/search/*”路由之后。

【讨论】:

我已经尝试重新排列路线,任何组合都可以正常工作,但只要存在 setHeader 行,仍然会导致下载。知道这是为什么吗? 不,抱歉,为什么是纯文本/文本而不是“文本/html”。也可以是“文本/纯文本”而不​​是“纯文本/文本”吗? developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/… 它可以是'text/plain',甚至是'text/html'。但是那些行为正常,它们不会触发下载。显然,它与您建议的 MIME 类型有关。实际上我根本不需要为我的项目设置标题,res.json() 涵盖了我需要的大部分内容。我只是在尝试不同的内容类型并且对下载感到好奇,为什么有些返回 `TypeError: invalid media type' 而有些只是将路由参数下载为文件。

以上是关于为啥某些无效的 MIME 类型会触发“TypeError”,而其他无效的 MIME 类型会绕过错误并触发自动下载?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查触发器是不是无效?

为啥 CSS 文件会以错误的 MIME 类型保存:text/troff?

为啥有这么多 mime 类型?

触发器级联为啥会失败

某些东西会在控制台中触发警告?为啥不推荐它,你将如何解决它?

与服务人员反应生产错误:无效的 MIME 类型