предисловие
Загрузка и скачивание все еще относительно распространены в веб-приложениях, будь то изображения или другие файлы. В Koa есть много промежуточного программного обеспечения, которое может помочь нам быстро реализовать функции.
Файл загружен
При загрузке файлов во фронтенде мы загружаем их через формы, и загруженные файлы нельзя передать через серверную часть, как обычные параметры.ctx.request.body
Получать. мы можем использоватьkoa-body
Промежуточное ПО для обработки загрузки файлов, оно может объединять тело запроса вctx.request
середина.
// 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 // 设置上传文件大小最大限制,默认2M
}
}));
app.listen(3001, ()=>{
console.log('koa is listening in 3001');
})
После использования промежуточного программного обеспечения вы можетеctx.request.body.files
чтобы получить содержимое загруженного файла. Следует отметить, что установлен maxFileSize, в противном случае будет сообщено об ошибке, как только загруженный файл превысит ограничение по умолчанию.
После получения файла нам нужно сохранить файл в каталоге и вернуть URL-адрес во внешний интерфейс. Процесс в узле
- Создайте читаемый поток
const reader = fs.createReadStream(file.path)
- Создать доступный для записи поток
const writer = fs.createWriteStream('upload/newpath.txt')
- Поток с возможностью чтения записывается в поток с возможностью записи через канал
reader.pipe(writer)
const router = require('koa-router')();
const fs = require('fs');
router.post('/upload', async (ctx){
const file = ctx.request.body.files.file; // 获取上传文件
const reader = fs.createReadStream(file.path); // 创建可读流
const ext = file.name.split('.').pop(); // 获取上传文件扩展名
const upStream = fs.createWriteStream(`upload/${Math.random().toString()}.${ext}`); // 创建可写流
reader.pipe(upStream); // 可读流通过管道写入可写流
return ctx.body = '上传成功';
})
Этот метод подходит для загрузки изображений, текстовых файлов, сжатых файлов и т. Д.
загрузка документа
koa-send
Это промежуточное программное обеспечение для службы статических файлов, которое можно использовать для реализации функции загрузки файлов.
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);
})
Есть два способа загрузки на переднем конце:window.open
и отправка формы. Вот более простойwindow.open
.
<button onclick="handleClick()">立即下载</button>
<script>
const handleClick = () => {
window.open('/download/1.png');
}
</script>
здесьwindow.open
По умолчанию открывается новое окно, мигает, а затем закрывается, пользовательский интерфейс не очень хорош, вы можете добавить второй параметрwindow.open('/download/1.png', '_self');
Это будет загружено прямо в текущем окне. Однако это должно заменить текущую страницу, которая вызоветbeforeunload
Дождитесь события страницы, если ваша страница прослушивает событие для выполнения некоторых операций, это окажет влияние. Затем вы также можете использовать скрытое окно iframe для достижения того же эффекта.
<button onclick="handleClick()">立即下载</button>
<iframe name="myIframe" style="display:none"></iframe>
<script>
const handleClick = () => {
window.open('/download/1.png', 'myIframe');
}
</script>
Пакетная загрузка
Нет никакой разницы между пакетной загрузкой и одиночной загрузкой, просто выполните еще несколько загрузок. Это действительно не проблема. Если так много файлов упаковано в сжатый пакет, а затем загружается только этот сжатый пакет, лучше ли это?
упаковка файлов
archiver
Это модуль, который может реализовать функцию упаковки на разных платформах в Node.js и поддерживает форматы zip и tar.
const router = require('koa-router')();
const send = require('koa-send');
const archiver = require('archiver');
router.post('/downloadAll', async (ctx){
// 将要打包的文件列表
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++) {
// 添加单个文件到压缩包
zip.append(fs.createReadStream(list[i].name), { name: list[i].name })
}
await zip.finalize();
ctx.attachment(zipName);
await send(ctx, zipName);
})
Если вы упаковываете всю папку напрямую, вам не нужно просматривать каждый файл, добавляемый к сжатому пакету.
const zipStream = fs.createWriteStream('1.zip');
const zip = archiver('zip');
zip.pipe(zipStream);
// 添加整个文件夹到压缩包
zip.directory('upload/');
zip.finalize();
Примечание. Запакуйте всю папку, сгенерированный сжатый файл пакета не сохраняется в этой папке, иначе он будет запакован.
проблема с китайской кодировкой
Если имя файла содержит китайский язык, могут возникнуть некоторые непредвиденные ситуации. Поэтому при загрузке, если он содержит китайский язык, я проверю имя файла.encodeURI()
Сохраните код и сделайте это, когда загрузите его.decodeURI()
расшифровать.
ctx.attachment(decodeURI(path));
await send(ctx, path);
ctx.attachment
Установите для параметра Content-Disposition значение «attachment», чтобы клиент запрашивал загрузку. Расшифрованное имя файла используется как имя загруженного файла для загрузки, так что он загружается на локальный, а китайское имя все еще отображается.
Гусь,koa-send
В исходном коде путь к файлу будетdecodeURIComponent()
расшифровка:
// koa-send
path = decode(path)
function decode (path) {
try {
return decodeURIComponent(path)
} catch (err) {
return -1
}
}
В это время путь, содержащий китайский язык, загружается после декодирования, а закодированный путь хранится на нашем сервере, поэтому, естественно, соответствующий файл не может быть найден.
Чтобы исправить это, не позволяйте ему декодировать. я хочу переехатьkoa-send
Если исходный код, вы можете использовать другое промежуточное ПОkoa-sendfile
замени это.
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);
})