mime-types vs content-type vs content-disposition vs http-errors vs mime vs type-is
Node.js HTTP 头部与 MIME 类型处理工具库对比
mime-typescontent-typecontent-dispositionhttp-errorsmimetype-is类似的npm包:

Node.js HTTP 头部与 MIME 类型处理工具库对比

content-disposition、content-type、http-errors、mime、mime-types 和 type-is 是一组专注于处理 HTTP 请求/响应中常见任务的轻量级 Node.js 工具库。它们分别用于生成或解析 Content-Disposition 头、解析或格式化 Content-Type 头、创建标准化 HTTP 错误对象、查询文件扩展名与 MIME 类型的映射、提供权威的 MIME 类型数据库,以及根据请求内容判断媒体类型。这些库通常被 Express 等 Web 框架内部使用,也可在中间件或自定义服务逻辑中直接调用,以确保符合 HTTP 规范并提升代码健壮性。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
mime-types259,791,7881,47322.9 kB289 个月前MIT
content-type194,021,81214423 kB25 天前MIT
content-disposition141,615,23824649.7 kB312 天前MIT
http-errors01,55819.1 kB209 个月前MIT
mime02,355161 kB61 年前MIT
type-is023021.3 kB73 个月前MIT

Node.js HTTP 头部与 MIME 类型处理工具库深度对比

在构建健壮的 Node.js Web 应用(尤其是使用 Express 或 Koa 时),正确处理 HTTP 头部、MIME 类型和错误响应至关重要。content-disposition、content-type、http-errors、mime、mime-types 和 type-is 这六个库虽小,却各自解决了一个关键问题。它们共同构成了现代 Web 框架底层的“HTTP 工具箱”。本文将深入剖析它们的功能差异、适用场景及协同方式。

📦 核心职责:各司其职的 HTTP 工具

每个库都聚焦于一个明确的 HTTP 相关任务:

  • content-disposition:生成安全的 Content-Disposition 响应头,用于控制浏览器如何处理响应内容(内联显示或作为附件下载)。
  • content-type:解析或格式化 Content-Type 请求/响应头,提取媒体类型和参数(如 charset)。
  • http-errors:创建标准化的 HTTP 错误对象,包含状态码、消息和可暴露性标记。
  • mime:提供完整的 MIME 类型数据库及双向查询(扩展名 ↔ MIME 类型),支持运行时修改。
  • mime-types:提供只读的 MIME 类型数据库查询接口,轻量高效。
  • type-is:根据请求的 Content-Type 判断其是否匹配给定的媒体类型模式(支持通配符)。

💡 注意:这些库均未被废弃,维护活跃,且被 Express 官方中间件广泛使用。

🔍 功能详解与代码示例

1. 文件下载:content-disposition vs 手动拼接

当提供文件下载时,Content-Disposition 头必须正确编码文件名以支持中文等特殊字符。手动拼接极易出错。

// ❌ 危险:手动拼接可能被注入或乱码
const filename = '报告.pdf';
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);

// ✅ 安全:使用 content-disposition 自动处理编码
const contentDisposition = require('content-disposition');
res.setHeader('Content-Disposition', contentDisposition('报告.pdf'));
// 输出: attachment; filename="%E6%8A%A5%E5%91%8A.pdf"; filename*=UTF-8''%E6%8A%A5%E5%91%8A.pdf

2. 解析媒体类型:content-type 的精准解析

Content-Type 头常包含参数(如 charset=utf-8),需结构化解析。

// 使用 content-type 解析
const contentType = require('content-type');
const parsed = contentType.parse('application/json; charset=utf-8');
// { type: 'application/json', parameters: { charset: 'utf-8' } }

// 反向生成标准格式
const formatted = contentType.format({ type: 'text/html', parameters: { charset: 'iso-8859-1' } });
// 'text/html; charset=iso-8859-1'

3. 标准化错误:http-errors 的语义化错误对象

抛出带状态码的错误,便于全局错误处理中间件识别。

const createError = require('http-errors');

// 创建 404 错误
throw createError(404, 'User not found');

// 创建 500 错误(默认不暴露细节)
throw createError.InternalServerError('Database connection failed');

// 错误对象属性
// err.status === 500
// err.expose === false (5xx 默认不暴露,4xx 默认暴露)

4. MIME 类型查询:mime vs mime-types

两者都基于 mime-db 数据库,但接口和能力不同。

// mime-types:只读查询
const mimeTypes = require('mime-types');
mimeTypes.contentType('.json'); // 'application/json'
mimeTypes.charset('text/html');  // 'UTF-8'

// mime:双向查询 + 运行时修改
const mime = require('mime');
mime.getType('file.json');      // 'application/json'
mime.getExtension('text/html'); // 'html'

// 添加自定义类型(仅 mime 支持)
mime.define({ 'application/x-custom': ['xc'] });

5. 内容类型检测:type-is 的灵活匹配

在中间件中根据请求体类型执行不同逻辑。

const typeis = require('type-is');

// 检查是否为 JSON
if (typeis(req, ['json'])) {
  // 处理 application/json
}

// 检查是否为文本类型(支持通配符)
if (typeis.is(req.headers['content-type'], ['text/*'])) {
  // 处理 text/plain, text/html 等
}

// 检查是否为特定 vendor 类型
if (typeis(req, 'application/vnd.api+json')) {
  // 处理 JSON:API
}

🤝 协同工作:典型使用场景

这些库常在 Web 框架中间件中协同工作。例如,一个文件上传处理流程:

  1. type-is 检查请求是否为 multipart/form-data。
  2. content-type 解析边界参数(boundary)。
  3. 上传完成后,mime-types 根据文件扩展名设置响应 Content-Type。
  4. 若需提供下载,content-disposition 生成安全的下载头。
  5. 若文件不存在,http-errors 抛出 404 错误。
// Express 中间件示例
app.use('/download/:filename', (req, res, next) => {
  const { filename } = req.params;
  const filePath = path.join(__dirname, 'uploads', filename);
  
  if (!fs.existsSync(filePath)) {
    return next(createError(404)); // http-errors
  }
  
  const mimeType = mimeTypes.contentType(path.extname(filename)); // mime-types
  res.setHeader('Content-Type', mimeType);
  res.setHeader('Content-Disposition', contentDisposition(filename)); // content-disposition
  
  res.sendFile(filePath);
});

⚖️ 选型指南:何时用哪个?

场景推荐库原因
生成文件下载头content-disposition自动处理编码,符合 RFC 标准
解析/生成 Content-Type 头content-type精确处理类型和参数
抛出带状态码的错误http-errors标准化错误对象,含 expose 语义
需要动态添加 MIME 类型mime支持运行时 define()
静态资源 MIME 查询mime-types轻量只读,接口简洁
按内容类型路由请求type-is支持通配符和复杂匹配

💡 最佳实践建议

  • 避免重复造轮子:这些库已处理了大量边缘情况(如 MIME 类型大小写、参数引号、特殊字符编码),直接使用比手写正则更可靠。
  • 组合使用:它们设计上互补,可安全组合(如 type-is 内部使用 mime-types)。
  • 关注安全:content-disposition 和 http-errors 的 expose 属性能有效防止信息泄露。
  • 性能考量:所有库均为同步操作,无 I/O 开销,适合高频调用。

📌 总结

这六个库虽小,却是构建符合 HTTP 规范的 Web 服务不可或缺的基石。它们分工明确:

  • 头部生成/解析:content-disposition、content-type
  • 错误标准化:http-errors
  • MIME 类型管理:mime(可写)、mime-types(只读)
  • 内容类型检测:type-is

在架构设计中,优先使用这些经过实战检验的工具,而非自行实现 HTTP 相关逻辑,能显著提升应用的健壮性、安全性和可维护性。

如何选择: mime-types vs content-type vs content-disposition vs http-errors vs mime vs type-is

  • mime-types:

    选择 mime-types 当你只需要快速、只读地查询标准 MIME 类型数据库(如根据扩展名获取类型,或检测某类型是否为文本类型),而无需修改数据库。它接口简洁、体积小,是大多数 Web 应用中处理静态资源 MIME 类型的首选。

  • content-type:

    选择 content-type 当你需要解析请求中的 Content-Type 头(如 application/json; charset=utf-8)为结构化对象,或从类型和参数反向生成标准格式的 Content-Type 字符串。它严格遵循 RFC 7231,适合需要精确处理媒体类型和字符集参数的中间件或 API 网关。

  • content-disposition:

    选择 content-disposition 当你需要安全地生成符合 RFC 6266 标准的 Content-Disposition 响应头,特别是为用户下载文件时指定文件名(支持自动处理特殊字符和非 ASCII 字符的编码)。它能避免手动拼接字符串带来的安全风险和兼容性问题,是处理文件下载场景的可靠选择。

  • http-errors:

    选择 http-errors 当你需要抛出带有标准 HTTP 状态码(如 404、500)和可读消息的错误对象。它生成的错误实例包含 status、statusCode 和 expose 属性,便于上层错误处理中间件统一格式化响应,是构建健壮 RESTful API 的基础组件。

  • mime:

    选择 mime 当你需要一个包含完整 MIME 类型数据库(基于 mime-db)且支持双向查询(扩展名 ↔ MIME 类型)的工具,并希望直接操作本地 MIME 类型定义(如添加自定义类型)。它比 mime-types 提供了更多运行时操作能力,适合需要动态扩展 MIME 映射的场景。

  • type-is:

    选择 type-is 当你需要根据请求的 Content-Type 头判断其是否匹配特定的媒体类型(如 json、text/* 或 application/vnd.api+json)。它支持通配符和子类型匹配,常用于中间件中按内容类型路由请求或验证请求体格式。

mime-types的README

mime-types

NPM Version NPM Downloads Node.js Version Build Status Test Coverage

The ultimate javascript content-type utility.

Similar to the [email protected] module, except:

  • No fallbacks. Instead of naively returning the first available type, mime-types simply returns false, so do var type = mime.lookup('unrecognized') || 'application/octet-stream'.
  • No new Mime() business, so you could do var lookup = require('mime-types').lookup.
  • No .define() functionality
  • Bug fixes for .lookup(path)

Otherwise, the API is compatible with mime 1.x.

Install

This is a Node.js module available through the npm registry. Installation is done using the npm install command:

$ npm install mime-types

Note on MIME Type Data and Semver

This package considers the programmatic api as the semver compatibility. Additionally, the package which provides the MIME data for this package (mime-db) also considers it's programmatic api as the semver contract. This means the MIME type resolution is not considered in the semver bumps.

In the past the version of mime-db was pinned to give two decision points when adopting MIME data changes. This is no longer true. We still update the mime-db package here as a minor release when necessary, but will use a ^ range going forward. This means that if you want to pin your mime-db data you will need to do it in your application. While this expectation was not set in docs until now, it is how the pacakge operated, so we do not feel this is a breaking change.

If you wish to pin your mime-db version you can do that with overrides via your package manager of choice. See their documentation for how to correctly configure that.

Adding Types

All mime types are based on mime-db, so open a PR there if you'd like to add mime types.

API

var mime = require('mime-types')

All functions return false if input is invalid or not found.

mime.lookup(path)

Lookup the content-type associated with a file.

mime.lookup('json') // 'application/json'
mime.lookup('.md') // 'text/markdown'
mime.lookup('file.html') // 'text/html'
mime.lookup('folder/file.js') // 'application/javascript'
mime.lookup('folder/.htaccess') // false

mime.lookup('cats') // false

mime.contentType(type)

Create a full content-type header given a content-type or extension. When given an extension, mime.lookup is used to get the matching content-type, otherwise the given content-type is used. Then if the content-type does not already have a charset parameter, mime.charset is used to get the default charset and add to the returned content-type.

mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
mime.contentType('file.json') // 'application/json; charset=utf-8'
mime.contentType('text/html') // 'text/html; charset=utf-8'
mime.contentType('text/html; charset=iso-8859-1') // 'text/html; charset=iso-8859-1'

// from a full path
mime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8'

mime.extension(type)

Get the default extension for a content-type.

mime.extension('application/octet-stream') // 'bin'

mime.charset(type)

Lookup the implied default charset of a content-type.

mime.charset('text/markdown') // 'UTF-8'

var type = mime.types[extension]

A map of content-types by extension.

[extensions...] = mime.extensions[type]

A map of extensions by content-type.

License

MIT