You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用fs.createReadStream()获取Content-Type?解决TS2339错误

问题:使用fs.createReadStream()时如何获取文件的Content-Type?

我把原本用fs.readFile()的代码改成fs.createReadStream()后,写了这段代码:

const filePath = "/home/a/bars/img1.png";

const uploadParams: { Bucket: string; Key: string; Body: string | ReadStream; ContentType: any; ACL: string } = {
  Bucket: bucketName,
  Key: '',
  Body: '',
  ContentType: null,
  ACL: 'public-read',
};

const fileStream = fs.createReadStream(filePath);
fileStream.on('error', function (err) {
  console.log('File Error', err);
});
uploadParams.Body = fileStream;
uploadParams.Key = path.basename(filePath);
uploadParams.ContentType = fileStream.mimetype; // 此处报错
uploadParams.ACL = 'public-read';

执行时遇到TypeScript错误:

Property 'mimetype' does not exist on type 'ReadStream'.ts(2339)

请问用fs.createReadStream()时该怎么获取文件的Content-Type?


解决方案

fs.ReadStream本身没有mimetype属性,你可以通过以下几种方式获取文件的Content-Type:

1. 通过文件扩展名推断

利用path模块获取文件扩展名,结合Node.js内置的mime模块(v14.17.0+内置)映射对应MIME类型:

import { createReadStream } from 'fs';
import { basename, extname } from 'path';
import { lookup } from 'mime';

const filePath = "/home/a/bars/img1.png";
const fileExt = extname(filePath);
const contentType = lookup(fileExt) || 'application/octet-stream';

const uploadParams = {
  Bucket: bucketName,
  Key: basename(filePath),
  Body: createReadStream(filePath),
  ContentType: contentType,
  ACL: 'public-read',
};

如果你的Node.js版本较低,也可以手动维护扩展名与MIME类型的映射表,比如:

const mimeMap: Record<string, string> = {
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.txt': 'text/plain'
};
const contentType = mimeMap[fileExt] || 'application/octet-stream';

2. 通过文件头签名(Magic Number)判断

如果文件没有扩展名或扩展名不准确,可以读取文件的前几个字节,根据文件签名推断真实MIME类型。你可以用第三方库file-type简化这个过程:

import { createReadStream } from 'fs';
import { basename } from 'path';
import { fileTypeFromFile } from 'file-type';

async function getUploadParams() {
  const filePath = "/home/a/bars/img1.png";
  const fileType = await fileTypeFromFile(filePath);
  const contentType = fileType?.mime || 'application/octet-stream';

  const uploadParams = {
    Bucket: bucketName,
    Key: basename(filePath),
    Body: createReadStream(filePath),
    ContentType: contentType,
    ACL: 'public-read',
  };
  return uploadParams;
}

这种方法是异步的,需要在async函数中调用。

3. 手动读取文件头实现

如果不想依赖第三方库,也可以自己读取文件前几个字节,对照文件签名表判断MIME类型。比如PNG文件的开头字节是89 50 4E 47,对应image/png:

import { createReadStream, readFileSync } from 'fs';
import { basename } from 'path';

function getContentType(filePath: string): string {
  const buffer = readFileSync(filePath, { byteLength: 8 });
  // 检查PNG签名
  if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) {
    return 'image/png';
  }
  // 可添加更多文件类型的签名判断
  return 'application/octet-stream';
}

const filePath = "/home/a/bars/img1.png";
const contentType = getContentType(filePath);

const uploadParams = {
  Bucket: bucketName,
  Key: basename(filePath),
  Body: createReadStream(filePath),
  ContentType: contentType,
  ACL: 'public-read',
};

内容的提问来源于stack exchange,提问作者best_of_man

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:02:50