Files
EchoChat/test-report-phase2d-bugfix.md

6.7 KiB
Raw Permalink Blame History

Phase 2d 富媒体消息 Bug 修复报告

修复日期2026-04-20 验证方式Playwright MCP 浏览器自动化 测试账号:前台 testuser1 / test123456、管理端 admin_test / admin123456


一、问题概述

用户在功能测试中反馈:图片上传、聊天发送图片报错,页面上无法看到图片消息。经 Playwright 自动化复现后,抓取到连锁的四处缺陷,全部已修复并通过端到端验证。


二、根因分析与修复

Bug 1文件上传请求指向错误端口ERR_CONNECTION_REFUSED

  • 现象POST http://localhost:8080/api/v1/upload/imageERR_CONNECTION_REFUSED
  • 根因frontend/src/api/file.jsBASE_URL 硬编码为 http://localhost:8080,与实际后端端口 :8085 不一致。
  • 修复:复用 @/utils/request.js 中的统一 BASE_URL,开发环境自动拼接 http://{hostname}:8085,生产环境走相对路径,由 Nginx 反代。
 *
 * BASE_URL 复用 @/utils/request 中的统一配置保证与业务接口一致
 * 开发环境http://{hostname}:8085生产环境相对路径由 Nginx 反代)
 */

import { useUserStore } from '@/store/user'
import { BASE_URL } from '@/utils/request'

Bug 2MinIO 存储桶默认 private图片 URL 返回 403

  • 现象:后端返回的 http://localhost:9000/echochat/...jpg 被 MinIO 以 403 Forbidden 拒绝匿名访问;前端 <uni-image> 因此无法加载图片。
  • 根因pkg/storage/minio.go 仅创建 bucket未设置 Bucket PolicyMinIO 默认对象为私有,必须带签名或登录凭据才能访问。
  • 修复:在启动时为 bucket 设置 public-read 策略(仅 s3:GetObject 匿名可达,上传仍须 AccessKey/SecretKey
// ensureBucketPublicRead 设置 bucket 的匿名公开读策略
// 允许匿名用户通过 HTTP GET 访问 bucket 内的对象s3:GetObject
// 其他操作(上传、删除等)仍然需要 AccessKey/SecretKey 凭据
func ensureBucketPublicRead(ctx context.Context, client *minio.Client, bucket string) error {
	policy := fmt.Sprintf(`{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"AWS": ["*"]},
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::%s/*"]
    }
  ]
}`, bucket)
	return client.SetBucketPolicy(ctx, bucket, policy)
}

Bug 3MsgImage 组件布局坍缩,图片不可见

  • 现象:即便 MinIO 可匿名访问后,bubble-media 宽度仅 12px、<uni-image> 宽度 0px图片无法可视化。
  • 根因MsgImage.vue.msg-image-wrap 为 flex 容器,但只设置了 max-width,未给 .grid-single 等宿主元素显式宽度;.img-thumb 使用 width:100% 在没有父级宽度参考时计算结果为 0导致气泡整体塌陷。
  • 修复:给 .grid-single / .grid-single .img-thumb 等增加 显式宽高400rpx × 300rpx 单图、156rpx × 156rpx 2 列、110rpx × 110rpx 3 列),并声明 display: block 以避免 inline-block 折行/塌陷。
.grid-single {
  width: 400rpx;
}
.grid-single .img-item {
  width: 100%;
  min-width: 200rpx;
  max-width: 400rpx;
}
.grid-single .img-thumb {
  width: 400rpx;
  height: 300rpx;
  border-radius: 12rpx;
  display: block;
}

Bug 4附带优化H5 下文件消息丢失原始文件名

  • 现象H5 下上传 test-doc.txt 后,聊天气泡显示为 file-1776653949262
  • 根因URL.createObjectURL(file) 生成的 blob URL 没有保留文件名,uni.uploadFile 把 blob 的临时名写回 fileHeader.Filename,后端据此生成的 result.file_name 丢失原名。
  • 修复:前端发送消息时优先使用用户选择的 file.name,仅当其为空时才回退到后端返回的 result.file_name。单聊 / 群聊 H5 及非 H5 分支同步修改。
          chatStore.sendFileMessage({
            conversationId: conversationId.value || 0,
            targetUserId: conversationId.value ? 0 : peerId.value,
            file: {
              url: result.url,
              // 优先使用前端原始文件名H5 下 blob URL 会丢失原名)
              file_name: file.name || result.file_name,
              size: result.size,
              mime_type: file.type || 'application/octet-stream',
              ext: '.' + (file.name.split('.').pop() || '')
            }
          })

三、Playwright 端到端验证

# 验证步骤 结果
1 修复前H5 上传图片,控制台报 ERR_CONNECTION_REFUSED @ :8080 已复现
2 修复 file.js 后:上传请求落到 :8085HTTP 200后端返回完整 url/thumbnail_url 通过
3 修复 MinIO 策略后:匿名 curl http://localhost:9000/.../_thumb.jpgHTTP 200 通过
4 修复 MsgImage 布局后:单聊气泡清晰显示缩略图,保持合理的气泡尺寸 通过
5 点击缩略图触发 uni.previewImage 弹出原图大图预览 通过
6 文件消息显示原始文件名 test-doc.txt48 B 通过
7 管理端 /#/message/list 列表显示图片 / 文件消息类型 通过
8 管理端消息详情弹窗:图片内联预览 + Extra 原始 JSON 正常 通过

四、受影响文件

文件 变更类型 说明
frontend/src/api/file.js 修改 BASE_URL 改为复用 @/utils/request 中的统一配置
backend/go-service/pkg/storage/minio.go 修改 增加 ensureBucketPublicRead 启动时设置 public-read 策略
frontend/src/components/msg/MsgImage.vue 修改 为单图/多图网格增加显式宽高,修正布局坍缩
frontend/src/pages/chat/conversation.vue 修改 文件消息优先使用前端原始文件名
frontend/src/pages/group/conversation.vue 修改 文件消息优先使用前端原始文件名H5 + 非 H5
test-report-phase2d-bugfix.md 新增 本次 Bug 修复报告

五、后续建议

  1. 生产环境部署MinIO 桶在生产集群也应保留 public-read 策略,或改为 CDN 前置缓存;若需私有鉴权(如临时签名 URL需改造后端 buildURLPresignedGetObject
  2. 错误提示增强uni.uploadFile 静默失败路径建议追加详细 uni.showToast(当前仅在 fail 分支提示),方便后续端到端问题定位。
  3. 文件名长度 / 特殊字符:现在直接使用 file.name 传回前端展示,需在 UI 上对超长文件名做省略(后续优化点)。