通过本机上传到Google Cloud Storage的本地反应图像不起作用,但邮递员请求起作用

问题描述 投票:0回答:1

[当我尝试通过我的node-express服务器从我的本机应用程序上载图像到Google Cloud Storage时遇到麻烦。使用邮递员图像上传没有任何问题,但是当我尝试使用Fetch / Axios上传图像时,我得到的错误消息仅为400。

这里是本机版本:

const fData = new FormData();
fData.append('image', {
        uri: imageFilePath,
        type: imagePickedType,
        file: imagePickedName
      });
fData.append('email', email);
fData.append('file', imagePickedName);
fData.append('type', imagePickedType);

const config = {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'multipart/form-data',
      },
      body: fData,
    };

fetch("http://192.168.43.194:3000/api/v1/auth/uploadavatar", config)
    .then(response  => response.json()).then(results => {      
      console.log("RespRespResp >>>> ", results);
    }).catch((error)=>{
      console.log("ErrorErrorError >>>", error);
    });

这就是邮递员的情况。成功上传状态为200的图片

enter image description here

这里是nodejs后端:

route v1.js:

const multer = Multer({
    storage: Multer.MemoryStorage,
    limits: {
      fileSize: 10 * 1024 * 1024, // Maximum file size is 10MB
    },
});


router.post('/auth/uploadavatar', multer.single('image'), gcsMiddlewares.sendUploadToGCS, auth.uploadAvatar);

GCS中间件:

const {Storage} = require('@google-cloud/storage');
const gcsHelpers = require('../helpers/google-cloud-storage');
const GOOGLE_CLOUD_PROJECT_ID = '************'; // Replace with your project ID
const path = require('path');
const GOOGLE_CLOUD_KEYFILE = ************; // Replace with the path to the downloaded private key

  // const storage = new Storage();

  const storage = new Storage({
      projectId: GOOGLE_CLOUD_PROJECT_ID,
      keyFilename: GOOGLE_CLOUD_KEYFILE,
  });

  const DEFAULT_BUCKET_NAME = '************'; // Replace with the name of your bucket

  /**
   * Middleware for uploading file to GCS.
   * @param {Object} req
   * @param {Object} res
   * @param {Function} next
   * @return {*}
   */
  exports.sendUploadToGCS = (req, res, next) => {
    if (!req.file) {
      return next();
    }

    const bucketName = req.body.bucketName || DEFAULT_BUCKET_NAME;
    const bucket = storage.bucket(DEFAULT_BUCKET_NAME);
    const gcsFileName = `${Date.now()}-${req.file.originalname}`;
    const file = bucket.file(gcsFileName);

    const stream = file.createWriteStream({
      metadata: {
        contentType: req.file.mimetype,
      },
    });

    stream.on('error', (err) => {
      req.file.cloudStorageError = err;
      next(err);
    });

    stream.on('finish', () => {
      req.file.cloudStorageObject = gcsFileName;

      return file.makePublic()
        .then(() => {
          req.file.gcsUrl = gcsHelpers.getPublicUrl(bucketName, gcsFileName);
          next();
        });
    });

    stream.end(req.file.buffer);
  };

../ helpers / google-cloud-storage.js:

/**
   * Copy file from local to a GCS bucket.
   * Uploaded file will be made publicly accessible.
   *
   * @param {string} localFilePath
   * @param {string} bucketName
   * @param {Object} [options]
   * @return {Promise.<string>} - The public URL of the uploaded file.
   */

  exports.getPublicUrl = (bucketName, fileName) => `https://storage.googleapis.com/${bucketName}/${fileName}`;

auth.uploadAvatar:

exports.uploadAvatar = (req, res, next) => {
    const state = req.body;
    if (req.file && req.file.gcsUrl) {
        state.avatarUrl = req.file.gcsUrl;
        return res.status(200).send(state);
    }
    return res.status(400).send({error: "Couldn't upload image"});
}

实际上,当我在我的react-native应用程序中使用Fetch / Axios时观察到的结果,在req.body中收到的图像具有此req结构,位于node-express后端,没有任何req.file:

body: [Object: null prototype] {
  email: '[email protected]',
  file: 'IMG-20191108-WA0000.jpg',
  type: 'image/jpeg',
  image: '����\u0000\u0010JFIF\u0000\u0001\u....' &TLDR
}

当我使用邮递员上传图像时,req的结构与req.body以及req.file一样:

body: [Object: null prototype] {},
file: {
    fieldname: 'image',
    originalname: '289489.png',
    encoding: '7bit',
    mimetype: 'image/png',
    buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 03 20 00 00 03 19 08 06 00 00 00 f8 05 50 0d 00 00 00 09 70 48 59 73 00 00 0b 13 00 00 0b 13 01 ... 1175161 more bytes>,
    size: 1175211
  }
node.js react-native axios google-cloud-storage fetch-api
1个回答
0
投票

首先初始化FormData,然后附加photo key。您需要传递file namefile type,然后传递uriuri是图像在设备上的位置。

只是归结为从file://上的uri剥离iOS。屋顶要传递给端点的其他数据(不是图片)

const inputFormData = (image, body) => {
  const fData = new FormData();

  fData.append("image", {
    name: image.fileName,
    type: image.type,
    uri:
      Platform.OS === "android" ? image.uri : image.uri.replace("file://", "")
  });

  Object.keys(body).forEach(key => {
    fData.append(key, body[key]);
  });

  return fData;
};

并且服务器必须修改接收数据的位置。图片的键具有三个值,但只有一个。

router.post('/auth/uploadavatar', multer.array('image', 3), gcsMiddlewares.sendUploadToGCS, auth.uploadAvatar);

用法

this.state={
   imageData : {
        uri: imageFilePath,
        type: imagePickedType,
        file: imagePickedName
      }
}
...
const config = {
      method: 'POST',
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      body: inputFormData(this.state.imageData, { email: email }),
    };
...
  fetch("http://192.168.43.194:3000/api/v1/auth/uploadavatar", config)
    .then(response => response.json())
    .then(results => {
       console.log("RespRespResp >>>> ", results)
    })
    .catch(error => {
      console.log("ErrorErrorError >>>", error);
    });
© www.soinside.com 2019 - 2024. All rights reserved.