简体   繁体   English

从 URL 获取图像并通过 NodeJS 中的 POST 上传到另一个

[英]Fetching image from URL and uploading to another via POST in NodeJS

In the following snippet, I'm using node-fetch and form-data to first retrieve an image file from a remote URL and then upload it to an S3 bucket (using aws-sdk and multer in a different script):在以下代码段中,我使用node-fetchform-data首先从远程 URL 检索图像文件,然后将其上传到 S3 存储桶(在不同的脚本中使用aws-sdkmulter ):

import fetch from 'node-fetch';
import fs from 'fs';
import FormData from 'form-data';

const form = new FormData();

const processProfileImg = (imageURL, userID) => {
  fetch(imageURL, userID)
    .then((response) => {
      const dest = fs.createWriteStream(`./temp/${userID}.jpg`);
      response.body.pipe(dest);
    })
    .then((dest) => {
      form.append('profileImage', fs.createReadStream(`./temp/${userID}.jpg`));
      fetch(`https://www.schandillia.com/upload/profile-image?userID=${userID}`, { method: 'POST', body: form })
        .then(response => response.json())
        .then(json => console.log(json));
    });
};

export default processProfileImg;

Problem is, this involves an intermediate step of first storing the file locally upon retrieval, before it's picked up for POST by the form-data function.问题是,这涉及一个中间步骤,即首先在检索时将文件存储在本地,然后再由form-data函数将其用于 POST。 Is there any way to bypass this step entirely?有没有办法完全绕过这一步? I don't want to save the file locally, I just want to pull it from the remote URL and POST it to the upload route without creating a local file.我不想将文件保存在本地,我只想从远程 URL 中提取它并将其 POST 到上传路由,而无需创建本地文件。

Update : After slightly modifying the snippet to implement suggestions from Fransebas (first answer) and avoid async issues, I'm running into a new problem: The image being saved locally is alright, but the copy being uploaded to S3 is partially cut off!更新:在稍微修改片段以实现 Fransebas(第一个答案)的建议并避免异​​步问题后,我遇到了一个新问题:本地保存的图像没问题,但上传到 S3 的副本被部分切断!

Additional code : The route that handles POST upload, https://www.schandillia.com/upload/profile-image , is as follows and it works well when I try uploading the file using Postman.附加代码:处理 POST 上传的路由https://www.schandillia.com/upload/profile-image如下,当我尝试使用 Postman 上传文件时,它运行良好。

import dotenv from 'dotenv';
import express from 'express';
import aws from 'aws-sdk';
import multerS3 from 'multer-s3';
import multer from 'multer';
import path from 'path';

dotenv.config();
const router = express.Router();

// Set up S3
const s3 = new aws.S3({
  accessKeyId: process.env.IAM_ACCESS_KEY_ID,
  secretAccessKey: process.env.IAM_SECRET_ACCESS_KEY,
});

const checkFileType = (file, cb) => {
  // Allowed ext
  const filetypes = /jpeg|jpg/;
  // Check ext
  const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
  // Check mime
  const mimetype = filetypes.test(file.mimetype);
  if (mimetype && extname) {
    return cb(null, true);
  }
  return cb('Error: JPEG Only!');
};

// Single Upload
const profileImgUpload = multer({
  storage: multerS3({
    s3,
    contentType: multerS3.AUTO_CONTENT_TYPE,
    bucket: `${process.env.S3_BUCKET_NAME}/w`,
    acl: 'public-read',
    key(req, file, cb) {
      cb(null, req.query.userID + path.extname(file.originalname));
    },
  }),
  limits: { fileSize: 2000000 }, // In bytes: 2000000 bytes = 2 MB
  fileFilter(req, file, cb) {
    checkFileType(file, cb);
  },
}).single('profileImage');

router.post('/profile-image', (req, res) => {
  profileImgUpload(req, res, (error) => {
    if (error) {
      console.log('errors', error);
      res.json({ error });
    } else if (req.file === undefined) {
      // If File not found
      console.log('Error: No File Selected!');
      res.json('Error: No File Selected');
    } else {
      // If Success
      const imageName = req.file.key;
      const imageLocation = req.file.location;
      // Save the file name into database into profile model
      res.json({
        image: imageName,
        location: imageLocation,
      });
    }
  });
});
// End of single profile upload

// We export the router so that the server.js file can pick it up
module.exports = router;

I haven't used that specific way of sending data (I prefer ajax) but by looking at your example I suppose you can skip saving the image locally. 我没有使用发送数据的特定方式(我更喜欢ajax),但是通过查看您的示例,我想您可以跳过本地保存图像。 If you see fs.createReadStream creates a read stream. 如果看到fs.createReadStream则会创建一个读取流。 Look for ways of creating a read stream from what you got. 寻找从您获得的内容中创建读取流的方法。

Also, I think you should put your sending code inside the then so you don't have async problems. 另外,我觉得你应该把你送代码中的then所以你不必异步问题。 For example, if your code for sending data is inside the then then you could use response.body to create the stream. 例如,如果您的用于发送数据的代码位于内, then可以使用response.body创建流。

You almost got it, but you are still using the file, I think you can archive it with something more like this 差不多了,但是您仍在使用该文件,我想您可以使用其他类似方式将其归档

import fetch from 'node-fetch';
import fs from 'fs';
import FormData from 'form-data';

const form = new FormData();

const processProfileImg = (imageURL, userID) => {
  fetch(imageURL, userID)
    .then((response) => {
      // Use response.body directly, it contains the image right?
      form.append('profileImage', response.body);
      fetch(`https://www.schandillia.com/upload/profile-image?userID=${userID}`, { method: 'POST', body: form })
        .then(response => response.json())
        .then(json => console.log(json));
    });
};

export default processProfileImg;

If I understand the documentation of fetch correctly response.body is already a stream. 如果我正确理解fetch文档,则response.body已经是一个流。

This works for me:这对我有用:

const axios = require('axios')
const FormData = require('form-data');

//Get image
let imageResponse = await axios({
    url: imageUrl,
    method: 'GET',
    responseType: 'arraybuffer'
})

//Create form data
const form = new FormData()
form.append('image', imageResponse.data, {
    contentType: 'image/jpeg',
    name: 'image',
    filename: 'imageFileName.jpg'
})

//Submit form
let result = await axios({
    url: serverUrl, 
    method: "POST",
    data: form, 
    headers: { "Content-Type": `multipart/form-data; boundary=${form._boundary}` }
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM