Fur*_*ous 3 http node.js npm multer
如何跟踪文件上传到NodeJs服务器的进度。我在服务器端使用multer上载文件。?
我是否需要向客户端发送某种信息,以便客户端获得上传进度,或者此操作在内部完成,客户端可以跟踪其进度。
以下是我用来上传文件的代码:
var multer = require('multer');
app.use(multer({dest:'./tmp',limits: {fileSize: 4*1024*1024}}).single('upload'));
router.post('/upload',function(req,res){
console.log(req.file);
});
Run Code Online (Sandbox Code Playgroud)
Multer 在跟踪文件上传进度方面不太灵活。我尝试了很多方法,使用进度流库来传输请求,制作自己的函数来计算百分比,然后将进度流式传输到 socket.io 等。socket.io 的方法(将百分比流式传输到套接字,然后返回客户端)在一定程度上发挥了作用,但主要问题是 Multer 在文件上传到服务器之前不会返回执行控制权,因此,如果您将其设置为中间件函数,例如:
this.router.post('/upload', upload.single('file'), function(req: Request, res: Response) {...}
Run Code Online (Sandbox Code Playgroud)
there's no way you're going to get the progress or req.file (if you try adding a middleware before upload.single like this.router.post('/upload', dosomething, upload.single('file')...), because req.file will not exist at that point, and afterwards it will be 100% once you try to access req.file. That's just how middlewares work. If you need to track the progress, but without sending it back to the client (which is not the case if you need a progress bar), then you can do something like I did below. BUT! this will work because you will be calculating the request size, not the req.file size (the req.file only exists in the context of Multer) Not that it makes much of a difference, the req and req.file come in the same request, so if you use the code below, you will see the percentage and then the code for saving the file with Multer will be run. An example of tracking the progress on the server size, would be:
var uploadImages = multer({ dest: ...}).single('...');
//more code ...
this.router.post('/upload', (req: Request, res: Response) => {
let progress = 0;
let fileSize = req.headers['content-length'] ? parseInt(req.headers['content-length']) : 0;
req.on('data', (chunk) => {
progress += chunk.length;
res.write((`${Math.floor((progress * 100) / fileSize)} `));
if (progress === fileSize) {
console.log('Finished', progress, fileSize)
}
});
})
//And calling the Multer function down here...
uploadImages(req,res...){}
Run Code Online (Sandbox Code Playgroud)
Calling the middleware function to upload a file with Multer, instead of using it in the route declaration, is specified in Multer's documentation (where it says "Error handling"). "If you want to catch errors specifically from Multer, you can call the middleware function by yourself."
The value of req.file will only exist in the context where the data has reached Multer for processing and saving. So what I recommend, to anyone trying to come up with an approach where you listen for the progress on the server side, if you can, and need to do it on the front-end, you can use Axios, which has a very good hook to keep track of the progress, for promises.
Example of sending Form Data and keeping track of the progress:
saveFile(file,url): Promise<...> {
let formData = new FormData();
formData.append('file', file);
const config = {
onUploadProgress: (progressEvent) => {
var percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
//do something with the percentCompleted
//I used an observable to pass the data to a component and subscribed to it, to fill the progressbar
}
}
return axios.post(url, formData, config)
}
Run Code Online (Sandbox Code Playgroud)
Hope it works for your needs, and helps you to avoid the headaches.
小智 6
工作代码
使用 Hooks 的 REACTJS 代码(前端)
upload.js或upload.jsx
import React, { useState } from "react";
import Axios from "axios";
import { Progress } from "reactstrap";
const Upload = () => {
const [uploadPercentage, setUploadPercentage] = useState(0);
const [showProgressBar, setProgressBarVisibility] = useState(false);
const onSubmit = e => {
e.preventDefault();
setProgressBarVisibility(true);
const demo = document.getElementById("demo");
const bodyFormData = new FormData(demo);
Axios({
headers: {
"Content-Type": "multipart/form-data",
},
method: "POST",
data: bodyFormData,
url: "/profile", // route name
baseURL: "http://localhost:5000/api/upload", //local url
onUploadProgress: progress => {
const { total, loaded } = progress;
const totalSizeInMB = total / 1000000;
const loadedSizeInMB = loaded / 1000000;
const uploadPercentage = (loadedSizeInMB / totalSizeInMB) * 100;
setUploadPercentage(uploadPercentage.toFixed(2));
console.log("total size in MB ==> ", totalSizeInMB);
console.log("uploaded size in MB ==> ", loadedSizeInMB);
},
encType: "multipart/form-data",
});
};
const handleFormClick = () => {
setProgressBarVisibility(false);
setUploadPercentage(0);
};
return (
<div>
<form onSubmit={e => onSubmit(e)} id="demo">
<input type="file" name="avatar" id="avatar" />
<input type="submit" value="Submit" />
</form>
{showProgressBar ? (
<>
<div className="text-center">
{parseInt(uploadPercentage) !== 100
? `Upload percentage - ${uploadPercentage}`
: "File successfully uploaded"}
</div>
<Progress
animated={parseInt(uploadPercentage) !== 100}
color="success"
value={uploadPercentage}
/>
</>
) : null}
</div>
);
};
export default Upload;
Run Code Online (Sandbox Code Playgroud)
NODEJS 代码(后端)
上传.js
const express = require("express");
const multer = require("multer");
const router = express.Router();
var storage = multer.diskStorage({
destination: "./uploads/",
filename: function(req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({ storage });
router.post("/profile", upload.single("avatar"), function(req, res, next) {
console.log(req.file);
if (req.file) {
return res.status(200).json(req.file);
}
return res.status(400).json({ msg: "PLEASE UPLOAD FILE" });
});
module.exports = router;
Run Code Online (Sandbox Code Playgroud)
小智 6
You can simply use a middleware to track progress of file upload.
We use this middleware before multer's middleware.
By this middleware, we set an event-listener for req object to track upload progress. then we call next to invoke the next middleware (Multer).
Here is the code:
const multer = require('multer');
const upload = multer({dest:'./tmp',limits: {fileSize: 4*1024*1024}});
function progress_middleware(req, res, next){
let progress = 0;
const file_size = req.headers["content-length"];
// set event listener
req.on("data", (chunk) => {
progress += chunk.length;
const percentage = (progress / file_size) * 100;
// other code ...
});
// invoke next middleware
next();
}
router.post('/upload', progress_middleware, upload.single('upload'), (req,res) => {
console.log(req.file);
});
Run Code Online (Sandbox Code Playgroud)
这是LinusU在项目github页面上的答案(他建议使用progress-stream):
将要求用管道输送到那个,然后加到搅拌器上。
var p = progress()
var upload = multer().single('file')
req.pipe(p)
p.headers = req.headers
p.on('progress', _)
upload(p, res, _)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4419 次 |
| 最近记录: |