Подтвердить что ты не робот

Отправка больших данных изображения через HTTP в Node.js

В моей среде разработки у меня есть два сервера. Один отправляет и изображение другому по запросу POST http.

Клиентский сервер делает это:

    fs.readFile(rawFile.path,'binary',function (err, file){
        restler.post("http://0.0.0.0:5000",{
            data: file,
            headers:{
                "Content-Type": rawFile.type,
            }
        }).on('complete',function(data,response){                               
            console.log(data);
            res.send("file went through")
        })

Сервер, который получает запрос, делает следующее:

    server.post('/',function(req,res,next){
        fs.writeFileSync("test.png",req.body,"binary",function(err){
            if(err) throw err;
            res.send("OK")
        })
    })

Если я отправлю небольшое изображение, он отлично работает. Однако, если я отправляю большое изображение, хотя файл сохраняется правильно, отображается только первая верхняя часть изображения. Остальное - черное. Правильный размер изображения.

Я предполагаю, что это только первый фрагмент изображения, который записывается в файл. Я попытался создать readStream и writeStream, но он не работает:

req.body.pipe(fs.createWriteStream('test.png'))

Могу ли я напрямую передавать данные из двоичных данных и pipe в файл? Для того, что я видел, readStream часто используется для потока из файлов, а не из исходных двоичных данных.

Я прочитал несколько сообщений , но, похоже, это не работает для меня.

Я использую модуль restler на клиентском сервере и restify в другом.

Спасибо!

4b9b3361

Ответ 1

Извините, что вы тупой, но здесь много чего.

readFile читает все содержимое файла в памяти перед вызовом обратного вызова, после чего вы начинаете загрузку файла.

Это плохо, особенно при работе с большими файлами, такими как images &ndash, потому что нет никаких оснований для чтения файла в памяти. Это расточительно; и при загрузке вы обнаружите, что на вашем сервере закончится память и сбой.

Вместо этого вы хотите получить поток, который испускает куски данных по мере чтения с диска. Все, что вам нужно сделать, это передать эти фрагменты вместе с вашим потоком загрузки (pipe), а затем отбросить данные из памяти. Таким образом, вы никогда не будете использовать больше, чем небольшое количество буферной памяти.

(Поведение чтения по умолчанию по умолчанию - обрабатывать необработанные двоичные данные, только если вы передаете encoding, который он использует в тексте.)

Модуль request делает это особенно просто:

fs.createReadStream('test.png').pipe(request.post('http://0.0.0.0:5000/'));

На сервере у вас большая проблема. Никогда не используйте методы * Sync.. Он блокирует ваш сервер от каких-либо действий (например, от ответа на другие запросы), пока весь файл не будет сброшен на диск, что может занять несколько секунд.

Поэтому вместо этого мы хотим принять входящий поток данных и передать его потоку файловой системы. Сначала вы были на правильном пути; причина, по которой req.body.pipe(fs.createWriteStream('test.png')) не работает, состоит в том, что body не является потоком.

body генерируется промежуточным программным обеспечением bodyParser. В обновлении это промежуточное ПО действует так же, как readFile, поскольку оно буферизует весь входящий объект-запрос в памяти. В этом случае мы этого не хотим. Отключите промежуточное ПО парсера тела.

Итак, где входной поток данных? Это сам объект req. restify Request наследует node http.IncomingMessage, который является читаемым потоком. Итак:

fs.createWriteStream('test.png').pipe(req);

Я также должен упомянуть, что все это работает так просто, потому что в нем нет элемента управления синтаксисом формы. запрос просто отправляет файл без оберток multipart/form-data:

POST / HTTP/1.1
host: localhost:5000
content-type: application/octet-stream
Connection: keep-alive
Transfer-Encoding: chunked

<image data>...

Это означает, что браузер не смог отправить файл на этот URL. Если это необходимо, загляните в formidable, который выполняет потоковой синтаксический анализ объектов-запросов.

Ответ 2

Я не знаю много о реставраторе. Но публикация изображения - это многопользовательский запрос.

restler.post("http://0.0.0.0:5000",{
    data: restler.file(path, filename, fileSize, encoding, contentType),
    multipart: true
})

Ответ 3

Я попробовал решение выше, и если вы просто перемещаете загруженные файлы или что-то другое, то следующее работает намного лучше:

fs.rename(path, newPath, callback(err) {});

Я загружал файлы более 200 МБ и сталкивался с ошибками с использованием потоков, синхронизации или асинхронизации.