У меня есть простой сервер 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 файлов (мой сценарий использования не сильно изменится), и он отлично работает,Единственное предположение, которое я могу сделать из этого, состоит в том, что есть какая-то ошибка от имени библиотеки.Я имею в виду, поскольку я не загружаю ни большие файлы, ни целую кучу файлов, я могу не использовать временные файлы.Но все же мне любопытно узнать, в чем может быть проблема, и если есть исправление или обходной путь, чтобы сделать это правильно.