为啥某些无效的 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/plain
或text/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?