【问题标题】:How to download after uploading a file using express and multer?使用 express 和 multer 上传文件后如何下载?
【发布时间】:2021-08-11 23:45:48
【问题描述】:

我已经使用multer将文件上传到我的后端filesystem

我的服务器是node,客户端是react

我无法在客户端react下载和显示保存的文件

每当我执行res.download(file) 时,它都会抛出一个错误,因为客户端连接被拒绝。

我的代码如下:

UserToUploadMapping.js

const mongoose = require("mongoose");

const UserToUploadMapping = new mongoose.Schema({
  userId: {
      type:String,
      required:true
  },
  file: {
    type: Object,
    required: true,
  },
  date: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model("UserToUploadMapping", UserToUploadMapping);

上传视频.js

const router = require("express").Router();
const multer = require('multer');
const UserToUploadMapping = require('../models/UserToUploadMapping')

let nameFile = ''
const storage = multer.diskStorage({
    destination:'./Videos',
    filename:(req,file,cb) => {
        console.log(file)
        nameFile = file.originalname + " "+ Date.now()
        cb(null, nameFile)
    }
})

const upload = multer({storage:storage})

router.post('/upload', upload.single('video'), async (req,res,next) => {
    console.log("object")
    const saveMapping = new UserToUploadMapping({
        userId:'123',
        file:req.file,
    })

    await saveMapping.save()

    res.send("Video uploaded")
})

router.get('/download', async(req,res,next) => {
    const x = await UserToUploadMapping.find()
    // res.send(x)
    res.download(x[0].path)
})

module.exports = router;

客户

const fetchVideo = async () => {
  
    const resp = await axios.get(
      "http://localhost:5000/api/user/video/download"
    );
    console.log(resp)
  };

  return (
    <>
      <NavContainer />
      <div className={classes.Post}>
        <Input
          type="file"
          onChange={(e) => uploadVideos(e.target.files)}
          accept="video/mp4"
        />
        {/* <Button onClick={(e) => submitHandler(e)}>Upload</Button> */}
        <video></video>
      </div>
    </>
  );

错误

【问题讨论】:

  • 请在问题中添加一条错误消息。
  • 错误:连接被拒绝。就是这么说的
  • localhost:5000 上似乎没有服务器。你如何运行快速服务器?
  • @quentino 快递服务器工作正常。只有下载路径失败..可能是因为我缺少在 axios 中设置一些配置?
  • 如果你有的话,你可以添加服务器日志,并检查你是否能够成功找到函数中的'x'

标签: javascript node.js express mongoose multer


【解决方案1】:

uploadVideo.js 文件中存在一些问题:

  • 要从数据中获取path,需要使用x[0].file.path

(基于您在数据库中保存文件的方式)

const saveMapping = new UserToUploadMapping({
        userId:'123',
        file:req.file,
    })
  • 为避免出现uploadVideo.js 文件在哪里以及我们在哪里运行应用程序的问题,在系统中保存文件时应使用绝对路径。
  • (小问题)您的filename 函数将给出类似video.mp4 1622180824748 的文件名。我认为这是更好的“video-1622181268053.mp4”(我们有正确的文件扩展名)

你可以参考这段代码

const router = require("express").Router();
const multer = require('multer');
const UserToUploadMapping = require('../models/UserToUploadMapping')
const path = require('path');
const uploadFolder = path.join(__dirname, "Videos"); // use a variable to hold the value of upload folder

const storage = multer.diskStorage({
    destination: uploadFolder, // use it when upload
    filename: (req, file, cb) => {
        // nameFile = file.originalname + " "+ Date.now() // --> give "video.mp4 1622180824748"
        let [filename, extension] = file.originalname.split('.');
        let nameFile = filename + "-" + Date.now() + "." + extension; // --> give "video-1622181268053.mp4"
        cb(null, nameFile)
    }
})

const upload = multer({ storage: storage })

router.post('/upload', upload.single('video'), async (req, res, next) => {
    const saveMapping = new UserToUploadMapping({
        userId: '123',
        file: req.file,
    })

    await saveMapping.save()

    res.send("Video uploaded")
})

router.get('/download', async (req, res, next) => {
    const video = await UserToUploadMapping.find({});
    res.download(video[0].file.path); // video[0].file.path is the absolute path to the file
})

module.exports = router;

【讨论】:

  • 虽然这个答案解决了后端的问题,但客户端仍然不完整,我面临问题..请回答客户端修改以使其工作,我会奖励你赏金
【解决方案2】:

您的代码表明您正在处理大文件(视频)。我强烈建议查看关注点分离,根据我的经验,不建议将其作为其他业务逻辑的一部分进行处理。这可以例如将来需要时使防火墙规则和 DDOS 保护复杂化。

至少,将上传和下载移动到自己的服务器中,例如'files.yourappnamehere.com' 以便您可以与业务逻辑 api 分开处理细节。

如果您在公共云中运行,我强烈建议您考虑重用 Blob 上传/下载功能,让您的客户端直接上传到 Blob 存储,并直接从 Blob 存储处理下载,例如在 Azure、AWS 或 GCP 中。

这将为您节省大量处理(非常)大文件的实现细节,并提供“免费”可扩展性选项,例如文件上传完成事件。

【讨论】:

  • 感谢您的洞察力.. 但是它根本不是一个大文件,这只是一个用于学习目的的项目.. 因为我是处理视频或图像上传的新手,所以我想尝试一下出
【解决方案3】:

您正在运行具有不同端口(3000、5000)的 2 个应用程序前端和后端,因此浏览器会阻止跨域请求。在 Express 上,您必须启用 CORS 以允许来自 FrontEnd Url (http://localhost:3000) 的请求。

【讨论】:

  • 我在问题中提到只有下载路径失败..其余一切正常,是的,我已经启用cors
【解决方案4】:

对于下载路径,请尝试使用window.location函数而不是Axios

【讨论】:

  • 请提供完整答案及代码
  • @Phil 您可以使用它直接在客户端启动下载。 window.location.assign(ROUTE_FOR_DOWNLOAD);您可以在这里找到更多解决方案:(stackoverflow.com/questions/1066452/…)
【解决方案5】:

看起来您的 get 处理程序中可能有错字...您引用了一个名为“路径”的元素,但未在架构中声明

router.get('/download', async(req,res,next) => {
    const x = await UserToUploadMapping.find()
    // res.send(x)
    res.download(x[0].path)//<-Path Doesn't seem to be in the schema
})

由于您在该函数中没有 try/catch,因此产生的错误可能会导致您的服务器停机,使其不可用

您可能还想查看此内容以了解有关How to download files using axios 的更多详细信息

【讨论】:

    猜你喜欢
    • 2016-10-22
    • 2017-03-01
    • 2015-10-11
    • 2018-07-21
    • 2016-01-16
    • 2017-11-12
    • 1970-01-01
    • 2016-06-14
    • 2018-05-17
    相关资源
    最近更新 更多