当前位置: 首页 > 知识库问答 >
问题:

前端使用uniapp直传minio,报错了?

皇甫飞光
2024-07-15
import { Client } from "minio";
import stream from "stream";

const minioClient = new Client({
  endPoint: "47.96.251.237",
  port: 9000,
  useSSL: false,
  accessKey: "ahct",
  secretKey: "ahct123456",
});
const bucketName = "test";
// const bucketName = BASE_URL === "http://47.96.251.237:80/prod-api" ? "ahctbucket" : "test";

export function toBlob(base64Data) {
  let byteString = base64Data;
  if (base64Data.split(",")[0].indexOf("base64") >= 0) {
    byteString = atob(base64Data.split(",")[1]);
  } else {
    byteString = unescape(base64Data.split(",")[1]);
  }
  const mimeString = base64Data.split(";")[0].split(":")[1];
  const uintArr = new Uint8Array(byteString.length);
  for (let i = 0; i < byteString.length; i++) {
    uintArr[i] = byteString.charCodeAt(i);
  }
  return new Blob([uintArr], { type: mimeString });
}

export function uploadImage({ file, onSuccess, onError }) {
  // const fileName = `${file.uid}-${file.name}`;
  const fileName = 'aaaa';
  const mimeType = file.type;
  const fileSize = file.size;
  const metadata = {
    "content-type": mimeType,
    "content-length": fileSize,
  };

  console.log("哈哈哈哈哈哈");

  minioClient.bucketExists(bucketName, (err) => {
    if (err) {
      if (err.code === "NoSuchBucket") {
        console.log("Bucket不存在");
        onError(err);
        return;
      }
      console.error("Error checking bucket existence:", err);
      onError(err);
      return;
    }
    console.log("Bucket存在");
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = (e) => {
      const dataurl = e.target.result;
      const blob = toBlob(dataurl);
      const reader2 = new FileReader();
      reader2.readAsArrayBuffer(blob);
      reader2.onload = (ex) => {
        const bufferStream = new stream.PassThrough();
        bufferStream.end(Buffer.from(ex.target.result));
        minioClient.putObject(
          bucketName,
          fileName,
          bufferStream,
          fileSize,
          metadata,
          (err, etag) => {
            if (err) {
              console.error("Error uploading object:", err);
              onError(err);
              return;
            }
            console.log("Object uploaded successfully, etag:", etag);
            minioClient.presignedGetObject(
              bucketName,
              fileName,
              24 * 60 * 60,
              (err, presignedUrl) => {
                if (err) {
                  console.error("Error getting presigned URL:", err);
                  onError(err);
                  return;
                }
                console.log("Presigned URL:", presignedUrl);
                const fileData = { url: presignedUrl, name: fileName };
                onSuccess(fileData);
              }
            );
          }
        );
      };
    };
  });
}

export function removeObject(fileName, callback) {
  minioClient.removeObject(bucketName, fileName, (err) => {
    if (err) {
      console.error("删除对象时出错:", err);
    } else {
      console.log("对象已成功删除", bucketName, fileName);
      callback();
    }
  });
}

uniapp小程序上传图片到minio报错信息:
哈哈哈哈哈哈

TypeError: global.XMLHttpRequest is not a constructor
    at define.push.module.exports.define.push.ClientRequest._onFinish (request.js?af32:166)
    at define.push.module.exports.<anonymous> (request.js?af32:62)
    at define.push.module.exports.emit (events.js?bf30:158)
    at finishMaybe (_stream_writable.js?edd4:630)
    at endWritable (_stream_writable.js?edd4:638)
    at define.push.module.exports.define.push.Writable.end (_stream_writable.js?edd4:594)
    at define.push.module.exports.define.push.ClientRequest.end (request.js?af32:297)
    at Readable.onend (_stream_readable.js?46dd:577)
    at Object.onceWrapper (events.js?bf30:242)
    at Readable.emit (events.js?bf30:153)(env: Windows,mp,1.06.2405020; lib: 3.4.10)

我想前端直传minio

共有2个答案

庞瀚
2024-07-15

minio.Client 不提供直接浏览器上传的方案。

不过有个有个折中方案:putObject 改为 presignedGetObject。

const url = await minioClient.presignedPutObject(bucketName, filename)

前端生成临时签名URL,再由前端进行上传。

image.png

题外话:非常不建议前端上传,秘钥都给出去了。如果练手没事。如果要上线安全还是要注重的。

尹正奇
2024-07-15

在 UniApp(特别是在小程序环境中)直接使用 minio 的 Node.js 客户端库可能会遇到问题,因为小程序环境并不完全等同于 Node.js 环境,特别是它不支持 global.XMLHttpRequest 这样的全局对象。UniApp 小程序环境提供了自己的 API 来处理网络请求和文件操作。

为了解决这个问题,你可以考虑以下方案:

  1. 使用 UniApp 提供的 uni.uploadFile API
    你可以使用 UniApp 提供的 uni.uploadFile API 来上传文件到 MinIO。你需要将文件转换为小程序可以识别的格式(通常是 FileBlob),然后使用 uni.uploadFile 将其发送到你的服务器(或 MinIO 的网关),该服务器将处理与 MinIO 的通信。
  2. 使用 MinIO 的网关
    你可以设置一个 MinIO 的网关(如 S3 网关),然后使用 UniApp 提供的 API 调用该网关。这通常意味着你需要在服务器端设置一个代理来处理与 MinIO 的通信。
  3. 修改 MinIO 客户端库
    如果你真的想从前端直接与 MinIO 通信(尽管这通常不推荐,出于安全和性能考虑),你可能需要修改 minio 客户端库以使其在小程序环境中工作。这可能需要大量的工作,并且可能仍然受到小程序环境的限制。
  4. 使用第三方库
    检查是否有专门为 UniApp 或小程序环境设计的第三方库,这些库可能已经解决了与 MinIO 通信的问题。

示例:使用 uni.uploadFile

以下是一个使用 uni.uploadFile API 上传文件的简化示例:

export function uploadImage({ file, onSuccess, onError }) {
  const uploadTask = uni.uploadFile({
    url: '你的服务器或MinIO网关的URL', // 例如:'http://your-server.com/upload'
    filePath: file.path, // 小程序中的文件路径
    name: 'file', // 文件对应的 key
    formData: {
      'user': 'test'
      // 其他你需要的表单数据
    },
    success: (res) => {
      if (res.statusCode === 200) {
        onSuccess(res.data); // 返回的上传结果
      } else {
        onError(new Error('上传失败'));
      }
    },
    fail: (err) => {
      onError(err);
    }
  });

  uploadTask.onProgressUpdate((res) => {
    console.log('上传进度', res.progress);
    // 可以在这里更新上传进度
  });
}

注意:在这个示例中,你需要将文件发送到你的服务器,然后你的服务器将文件转发到 MinIO。或者,如果你的服务器已经配置了 MinIO 的 S3 网关,你可以直接将文件发送到该网关。

 类似资料: