当前位置:网站首页>Koa file upload and download

Koa file upload and download

2022-06-13 04:04:00 Shadow night with the wind

Upload and download in web It is common in applications , Whether it's pictures or other files . stay koa2 in , We can use middleware to help us realize functions quickly

Upload files

Upload files on the front end , We all upload through forms , And upload files , On the server side, it is not possible to pass... Like normal parameters ctx.request.body obtain

We can use koa-body Middleware to handle file uploading , The request body can be spliced into ctx.request in .

 

//app.js

const koa =require("koa")

const app = new koa()

const koaBody = require("koa-body")

app.use(koaBody({

    multipart:true,

    formidable:{

    maxFileSize:200*1024*1024

    }

  })
)

app.listen(3000,()=>{

    console.log("koa is listening on 3000!")

})

 

After using middleware , You can use ctx.request.body.files Get the content of the uploaded file

It should be noted that the settings maxFileSize, Otherwise, an error will be reported when the uploaded file exceeds the default limit .

After receiving the file , We need to save the file to a directory , Return to one url To the front end . stay node The process in is

  1. Create a readable stream  const reader = fs.createReadStream(file.path)

  2. Create a writable stream  const writer = fs.createWriteStream('upload/newpath.txt')

  3. The readable stream writes the writable stream through the pipeline  reader.pipe(writer)

const router = require('koa-router')()

const fs = require('fs')

router.post('/unload',async(ctx){

    const file = ctx.request.body.files.file;// Get the upload file 

    const reader = fs.createReadStream(file.path);// Create a readable stream 

    const ext = file.name.split('.').pop();// Get the extension of the uploaded file 

    const upStream = fs.createWriteStream(`upload/${Math.random().toString()}.${ext}`);

    reader.pipe(upStream);

return ctx.body = ' Upload successful '; 

})

 

koa-body Is to put the uploaded file into the temporary file of the system , Then we read from the temporary file upload/ Under the table of contents . Actually koa-body You can also use formidable.uploadDir Property to set the storage directory directly

app.use(koaBody({

multipart: true,

formidable: {

maxFileSize: 200*1024*1024, //  Set the maximum upload file size limit , Default 2M

uploadDir: 'upload/',

onFileBegin: (name, file)=>{ //  Rename the file before storing it 

const fileFormat = file.name.split('.');

file.name = `${Date.now()}.${fileFormat[fileFormat.length-1]}`

file.path = `upload/${file.name}`;

}

}

}));

Then you can go through ctx.request.body.files.file Get the uploaded file directly .

const router = require('koa-router')();

const fs = require('fs');

router.post('/upload', async (ctx){

const file = ctx.request.body.files.file; //  Get the upload file 

return ctx.body = file.path; // upload/xxx.xx

})

 

File download

 

koa-send  Is a middleware of static file service , It can be used to realize the file download function .

const router = require('koa-router')();

const send = require('koa-send');

router.post('/download/:name', async (ctx){

const name = ctx.params.name;

const path = `upload/${name}`;

ctx.attachment(path);

await send(ctx, path);

})

Download on the front end , There are two ways : window.open  And form submission . Here we use the simpler  window.open.

<button onclick="handleClick()"> Download now </button>

<script>

const handleClick = () => {

window.open('/download/1.png');

}

</script>

 

here  window.open  The default is to open a new window , Flash and close , The user experience is not good , You can add a second parameter  window.open('/download/1.png', '_self');, In this way, it will be downloaded directly in the current window . However, this will url Replace the current page , It triggers  beforeunload  Wait for page Events , If your page listens to the event and does something , That will have an impact . Then you can also use a hidden iframe Window to achieve the same effect .

<button onclick="handleClick()"> Download now </button>

<iframe name="myIframe" style="display:none"></iframe>

<script>

const handleClick = () => {

window.open('/download/1.png', 'myIframe');

}

</script>

 

Bulk download

There is no difference between a batch download and a single download , Just perform a few more downloads . This is really no problem . If you pack so many files into a compressed package , Just download the compressed package , Is it better to experience .

collect files

archiver  It's a Node.js Modules that can realize packaging functions across platforms , Support zip and tar Format

const router = require('koa-router')();

const send = require('koa-send');

const archiver = require('archiver');

router.post('/downloadAll', async (ctx){

//  List of files to be packaged 

const list = [{name: '1.txt'},{name: '2.txt'}];

const zipName = '1.zip';

const zipStream = fs.createWriteStream(zipName);

const zip = archiver('zip');

zip.pipe(zipStream);

for (let i = 0; i < list.length; i++) {

//  Add a single file to a compressed package 

zip.append(fs.createReadStream(list[i].name), { name: list[i].name })

}

await zip.finalize();

ctx.attachment(zipName);

await send(ctx, zipName);

})

 

 

If you package the entire folder directly , You don't need to traverse every file append To the compressed package

const zipStream = fs.createWriteStream('1.zip');

const zip = archiver('zip');

zip.pipe(zipStream);

//  Add the entire folder to the package 

zip.directory('upload/');

zip.finalize();

Be careful : Pack the entire folder , The generated compressed package file cannot be stored in this folder , Otherwise, it will continue to pack .

 

Chinese coding problem

When the file name contains Chinese , There may be some unexpected situations . So when uploading , If it contains Chinese, I will change the file name  encodeURI()  Code to save , Download it before  decodeURI()  Decrypt .

ctx.attachment(decodeURI(path));

awaitsend(ctx, path);

 

ctx.attachment  take Content-Disposition Set to “ The attachment ” To instruct the client to prompt for download . Download the decoded file name as the name of the downloaded file , In this way, it can be downloaded locally , The Chinese name is still displayed .

Ran goose ,koa-send  In the source code , The file path will be  decodeURIComponent()  decode

// koa-send

path = decode(path)

function decode (path) {

try {

return decodeURIComponent(path)

} catch (err) {

return -1

}

}

 

At this time, download the path containing Chinese after decoding , The encoded path is stored in our server , Naturally, the corresponding file cannot be found .

To solve this problem , Then don't let it decode . Don't want to move  koa-send  Source words , Another middleware can be used  koa-sendfile  Instead of it .

const router = require('koa-router')();

const sendfile = require('koa-sendfile');

router.post('/download/:name', async (ctx){

const name = ctx.params.name;

const path = `upload/${name}`;

ctx.attachment(decodeURI(path));

await sendfile(ctx, path);

})

 

// Upload a single file :

router.post('/uploadfile', async (ctx, next) => {

//  Upload a single file 

const file = ctx.request.files.file; //  Get the upload file 

//  Create a readable stream 

const reader = fs.createReadStream(file.path);

let filePath = path.join(__dirname, 'public/upload/') + `/${file.name}`;

//  Create a writable stream 

const upStream = fs.createWriteStream(filePath);

//  The readable stream writes the writable stream through the pipeline 

reader.pipe(upStream);

return ctx.body = " Upload successful !";

});

 Upload multiple files :

router.post('/uploadfiles', async (ctx, next) => {

//  Upload multiple files 

const files = ctx.request.files.file; //  Get the upload file 

for (let file of files) {

//  Create a readable stream 

const reader = fs.createReadStream(file.path);

//  Get the extension of the uploaded file 

let filePath = path.join(__dirname, 'public/upload/') + `/${file.name}`;

//  Create a writable stream 

const upStream = fs.createWriteStream(filePath);

//  The readable stream writes the writable stream through the pipeline 

reader.pipe(upStream);

}

return ctx.body = " Upload successful !";

});

 

原网站

版权声明
本文为[Shadow night with the wind]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202280526046587.html