Загрузка нескольких файлов на сервер express.js с использованием временных файлов - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть простой сервер express.js и приложение внешнего интерфейса Angular7 (стек MEAN).На определенной странице я хочу разрешить пользователю загружать несколько файлов.Для загрузки файлов на сервер я использую пакет узла express-fileupload .Угловая сторона работает просто отлично, файлы отправляет правильно, 103% проверено.Однако экспресс-сторона доставляет мне трудные времена.

Итак, я гуглял уже как минимум 3 дня, и, похоже, ничего не помогло.Позвольте мне сначала сделать подробный набросок того, что я делаю:

Как я уже сказал, с угловой стороны все в порядке.На стороне сервера, чтобы настроить библиотеку загрузки файлов, я делаю это в app.js:

import fileupload from "express-fileupload";
...
app.use
(
    fileupload
    ({
        createParentPath: true,
        limits: { fileSize: 25 * 1024 * 1024 },
        useTempFiles: true,
        tempFileDir: "\\..\\..\\..\\tmp\\", // don't mind this, just temporary storing files here while developing, practical reasons
        safeFileNames: true,
        preserveExtension: 10,
        abortOnLimit: true,
        parseNested: true
    })
);

После этого у меня есть маршрутизатор в разделе «/ dev», что приводит к этому:

import express from "express";
import fileupload from "express-fileupload";
import path from "path";
...
let router = express.Router();
...
router.post("/upload", (req, res, next) =>
{
    let code: number = 200;
    let response =
    {
        result: "danger",
        message: "Could not upload file(s)."
    };

    if (req.files)
    {
        // since angular is sending the files with names 'files[0]', 'files[1]', ... (see below), and since 'parseNested' is true
        // (from the documentation on the link I provided above, it will compress all files in one array whose name is just 'files', so this cast is ok
        let uploads = <{ files: fileupload.UploadedFile[] }>req.files;
        let success = true;

        for (let i = 0; i < uploads.files.length; ++i)
        {
            uploads.files[i].mv(path.join(__dirname, "../../images/", uploads.files[i].name), err => success = err ? false : success);
        }

        if (success)
        {
            response.result = "success";
            response.message = "Files were uploaded successfully.";
        }
    }

    return res.status(code).json(response);
});

В угловом выражении я отправляю файлы примерно так:

import { HttpClient } from "@angular/common/http";
...
public constructor(private http: HttpClient) { }
...
// 'files' is coming from <input type="file" ...> html element, and the callback is not important
upload(files: FileList, callback: CallbackFunction)
{
    let form: FormData = new FormData();
    for (let i = 0; i < files.length; ++i)
        form.append("files[" + i + "]", files[i], files[i].name);

    this.http.post("/dev/upload", form).subscribe(callback);
}

Теперь вот странная вещь, которая происходит.Этот код полностью работает, когда я загружаю только 1 файл.Однако, если я выберу несколько файлов в моемэлемент, это исключение всплывает (на сервере) и выключает сервер:

Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    at writeAfterEnd (_stream_writable.js:248:12)
    at WriteStream.Writable.write (_stream_writable.js:296:5)
    at FileStream.<anonymous> (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\express-fileupload\lib\tempFileHandler.js:32:17)
    at FileStream.emit (events.js:182:13)
    at addChunk (_stream_readable.js:287:12)
    at readableAddChunk (_stream_readable.js:268:11)
    at FileStream.Readable.push (_stream_readable.js:223:10)
    at PartStream.onData (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\busboy\lib\types\multipart.js:223:28)
    at PartStream.emit (events.js:182:13)
    at addChunk (_stream_readable.js:287:12)
    at readableAddChunk (_stream_readable.js:268:11)
    at PartStream.Readable.push (_stream_readable.js:223:10)
    at Dicer._oninfo (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\dicer\lib\Dicer.js:191:36)
    at SBMH.<anonymous> (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\dicer\lib\Dicer.js:127:10)
    at SBMH.emit (events.js:182:13)
    at SBMH._sbmh_feed (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\streamsearch\lib\sbmh.js:188:10)
    at SBMH.push (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\streamsearch\lib\sbmh.js:56:14)
    at Dicer._write (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\dicer\lib\Dicer.js:109:17)
    at doWrite (_stream_writable.js:415:12)
    at writeOrBuffer (_stream_writable.js:399:5)
    at Dicer.Writable.write (_stream_writable.js:299:11)
    at Multipart.write (D:\Desktop\projects\job-fair\src\jf-backend\node_modules\busboy\lib\types\multipart.js:290:24)
Emitted 'error' event at:
    at errorOrDestroy (internal/streams/destroy.js:98:12)
    at writeAfterEnd (_stream_writable.js:250:3)
    at WriteStream.Writable.write (_stream_writable.js:296:5)
    [... lines matching original stack trace ...]
    at Dicer.Writable.write (_stream_writable.js:299:11)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! jf-backend@0.0.0 start: `tsc&node ./bin/www`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the jf-backend@0.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\vladi\AppData\Roaming\npm-cache\_logs\2019-02-04T21_51_27_602Z-debug.log

Чтобы сделать еще более странным, когда я делаю это:

import fileupload from "express-fileupload";
...
app.use
(
    fileupload
    ({
        createParentPath: true,
        limits: { fileSize: 25 * 1024 * 1024 },
        //useTempFiles: true,
        //tempFileDir: "\\..\\..\\..\\tmp\\",
        safeFileNames: true,
        preserveExtension: 10,
        abortOnLimit: true,
        parseNested: true
    })
);

Исключение неполучить один и тот же код, даже если я загружаю несколько файлов.Так что, как мне кажется, если я не использую временные файлы & tmp dir, загрузка работает просто отлично, я попытался загрузить 5-6 файлов (мой сценарий использования не сильно изменится), и он отлично работает,Единственное предположение, которое я могу сделать из этого, состоит в том, что есть какая-то ошибка от имени библиотеки.Я имею в виду, поскольку я не загружаю ни большие файлы, ни целую кучу файлов, я могу не использовать временные файлы.Но все же мне любопытно узнать, в чем может быть проблема, и если есть исправление или обходной путь, чтобы сделать это правильно.

...