Chrome 浏览器无法显示苹果上传图片的原因

Plan: Chrome 无法显示上传图片的根因诊断与修复

TLDR: HTTP 200 已确认表明 Express.static 静态服务正确找到了文件。

真正的问题是:iOS 设备在"高效格式"摄像模式下拍摄的照片实际是 HEIC/HEIF 格式 ,上传时浏览器或 iOS 仍以 .jpeg 作为文件名发送------Chrome 不支持 HEIC 格式解码,因此显示破损黑屏。

macOS Preview 和 Safari 原生支持 HEIC,所以文件在宿主机上看起来"存在且正常",但 Chrome 无法渲染。


第一阶段:确认根因

步骤 1 --- 在宿主机终端执行,确认文件真实格式:

bash 复制代码
file /文件路径/att-1774505932244-769917788.jpeg

若输出包含 HEIF imageISO Media,则确认为 HEIC 格式。

步骤 2(可选确认) --- Chrome DevTools → Network → 找到该请求 → Response Headers → 确认 Content-Type: image/jpeg(MIME 类型是 jpeg,但内容是 HEIC 字节,Chrome 解码失败)。


第二阶段:修复

步骤 1 --- 安装 sharp 库(Node.js 图片处理,支持 HEIC→JPEG 转换):

bash 复制代码
npm install sharp
npm install --save-dev @types/sharp

步骤 2 --- 修改 attachment.controller.ts

在 Multer 完成文件写入磁盘之后、入库之前,用 sharp 将 HEIC/HEIF 文件就地转换为标准 JPEG。核心逻辑:

  • 判断 file.mimetype 是否为 image/heicimage/heif,或者检测文件头字节
  • 若是 HEIC,则用 sharp(file.path).jpeg().toFile(tmpPath) 转换后替换原文件
  • 更新 file.mimetypeimage/jpegfile.size 为转换后大小

步骤 3 --- 修改 main.ts

useStaticAssets 的相对路径改为绝对路径(Docker 环境最佳实践,避免 process.cwd() 在不同环境下解析不一致):

现状:

typescript 复制代码
app.useStaticAssets('uploads', { prefix: '/uploads' });

改为(在文件顶部 import join):

typescript 复制代码
import { join } from 'path';
// ...
app.useStaticAssets(join(__dirname, '..', 'uploads'), { prefix: '/uploads' });

__dirname 在 Docker 中为 /usr/src/app/distjoin(__dirname, '..', 'uploads') = /usr/src/app/uploads,与 Docker Volume 挂载路径完全一致。

步骤 4 --- 重新构建并启动容器:

bash 复制代码
docker-compose up --build

相关文件

  • main.ts --- 修改 useStaticAssets 路径为绝对路径
  • attachment.controller.ts --- 在 uploadFile 方法中添加 HEIC→JPEG 转换逻辑

验证步骤

  1. 先执行 file 命令确认 HEIC 假设成立
  2. 重建 Docker 镜像后,重新上传一张 iOS 照片
  3. 在 Chrome 中通过 URL 访问该图片,确认正常显示

决策说明

  • 不修改 Multer 的 destination 配置 :文件先存到 uploads/attachments/,存入后立即原地转换,文件名保持不变,路径不受影响
  • 对非图片文件(PDF 等):需在转换逻辑中判断 mimetype,跳过非图片类型
  • 旧的损坏文件:无需处理,用户只需重新上传即可

相关推荐
猫猫不是喵喵.19 分钟前
Vue2 的 Vuex 状态管理与 Vue3 的 Pinia 状态管理
前端·javascript·vue.js
greenbbLV32 分钟前
中小公司积分商城选型:SaaS与私有化方案对比解析
大数据·前端·小程序
NutShell Wang2 小时前
Vite 8.1 深度拆解:Rolldown 统一打包器如何终结前端构建的「双引擎时代」
前端·rust·开源·vite·开发者工具·vibe coding
朱容zr3331332 小时前
请解释“回表”的概念。
java·前端·数据库
leslie1182 小时前
webpack笔记
前端·webpack
宁风NF2 小时前
JavaScript:内存、垃圾回收、性能优化
开发语言·前端·javascript·学习·性能优化·es6
勾勾圈圈蛋蛋2 小时前
DOM、BOM、DOM操作详解 + 结合Vue响应式关联梳理
前端
打妖妖灵滴哪吒3 小时前
IOS模态窗口的作用与设计原则
前端·ui
午安~婉3 小时前
挑战二:博客预览卡片
前端·javascript·html
环境栈笔记3 小时前
指纹浏览器安全评测方法:核对环境、数据与权限后再选型
前端·人工智能·后端·自动化