#javascript #node.js #mongodb #html5-audio #gridfs
#javascript #node.js #mongodb #html5-аудио #gridfs
Вопрос:
Для моего проекта я пытаюсь создать аудиоплеер. Аспект хранения файлов в базе данных для меня новый, поскольку раньше я сохранял только строки.
До сих пор то, что я смог сделать, это:
-
Сохраните аудиофайл в базе данных.(Я ссылаюсь здесь на файл для простоты, но в будущем он будет загружен)
-
Извлеките аудиофайл как объект.
-
Сохраните аудиофайл в общедоступной папке для использования.
Код на стороне сервера(код маршрута отделен от кода сервера)
let fs = require('fs');
var bodyParser = require('body-parser')
var urlencodedParser = bodyParser.urlencoded({
extended: false
})
const MongoClient = require('mongodb').MongoClient;
const Binary = require('mongodb').Binary;
const ObjectId = require('mongodb').ObjectId;
module.exports = function(app) {
app.get('/music', function(req, res) {
//STEP ONE
var data = fs.readFileSync(__dirname '/../public/recordings/Piso 21 - Puntos Suspensivos.mp3');
var insert_data = {};
insert_data.name = 'Piso 21 - Puntos Suspensivos.mp3';
insert_data.file_data = Binary(data);
MongoClient.connect("mongodb://localhost/songs", {
useNewUrlParser: true
}, function(err, db) {
if (err) throw err;
var dbo = db.db("songs");
dbo.collection("song").insertOne(insert_data, function(err, res) {
if (err) throw err;
console.log("1 document inserted");
db.close();
});
});
//STEP TWO
MongoClient.connect("mongodb://localhost/songs", {
useNewUrlParser: true
}, function(err, db) {
if (err) throw err;
var dbo = db.db("songs");
dbo.collection("song").findOne({
name: 'Piso 21 - Puntos Suspensivos.mp3'
}, function(err, result) {
if (err) throw err;
db.close();
//STEP THREE
fs.writeFile(result.name, result.file_data.buffer, function(err) {
if (err) throw err;
console.log(result);
});
});
});
res.render('audio');
});
Третий шаг — это то, что я не знаю, что делать. Я хотел бы отправить result
объект на audio.ejs
страницу и каким-то образом предоставить audio tag
доступ к нему без необходимости сохранять его в общедоступной папке, а затем удалять его после использования.
Что-то вроде этого,
ШАГ ТРЕТИЙ
res.render('audio', result);
и каким-то образом предоставить audio tag
доступ к нему на audio.ejs
странице
Обновить
let fs = require('fs');
var bodyParser = require('body-parser')
var urlencodedParser = bodyParser.urlencoded({ extended: false })
const MongoClient = require('mongodb');
const Binary = require('mongodb').Binary;
const ObjectId = require('mongodb').ObjectId;
const Grid = require('gridfs-stream');
const db = new MongoClient.Db('songs', new MongoClient.Server("localhost", 27017));
const gfs = Grid(db, MongoClient);
const bcrypt = require('bcryptjs');
module.exports = function(app){
app.get('/audio/:filename', function (req, res) {
MongoClient.connect("mongodb://localhost/songs", { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("songs");
dbo.collection("song").findOne({name: req.params.filename}, function(err, result){
if (err) throw err;
db.close();
const readstream = gfs.createReadStream(result.file_data);
readstream.on('error', function (error) {
res.sendStatus(500);
});
console.log(res);
res.type('audio/mpeg');
readstream.pipe(res);
});
});
});
Ответ №1:
На старинном жаргоне баз данных мультимедийные объекты называются BLOBS — двоичными большими объектами. В Mongo они обрабатываются с помощью подсистемы, известной как gridfs
. Для упрощения этого есть хороший модуль npm под названием gridfs-stream.
Простой способ доставки медиаобъектов в браузеры — сделать их доступными по URL-адресам, которые выглядят как https://example.com/audio/objectname.mp3
. И они должны быть доставлены с соответствующим Content-Type
заголовком для используемого кодека ( audio/mpeg
для MP3). Тогда тег src может просто назвать URL-адрес, и все будет в порядке. Тег audio на странице браузера выглядит примерно так:
<audio controls src="/audio/objectname.mp3" ></audio>
Итак, если вы хотите доставлять аудио напрямую через express, вам нужен маршрут с параметром, что-то вроде
app.get('/audio/:filename', ...
Тогда программа node использует что-то подобное, не отлаженное!)
const mongo = require('mongodb');
const Grid = require('gridfs-stream');
...
const db = new mongo.Db('yourDatabaseName', new mongo.Server("host", 27017));
const gfs = Grid(db, mongo);
...
app.get('/audio/:filename', function (req, res) {
const readstream = gfs.createReadStream({filename: req.params.filename})
readstream.on('error', function (error) {
res.sendStatus(500)
})
res.type('audio/mpeg')
readstream.pipe(res)
});
Это круто, потому что потоки — это круто: вашей узловой программе не нужно загружать весь аудиофайл в оперативную память. Аудиофайлы могут быть большими.
gridfs предлагает mongofiles
утилиту командной строкиy для загрузки файлов в gridfs.
Но, учитывая все сказанное: большинство масштабируемых медиасервисов используют статические медиафайлы, доставляемые из файловых систем и / или сетей доставки контента. Такие серверы, как apache и nginx, многие годы программистов были потрачены на то, чтобы сделать доставку файлов быстрой и эффективной. В базе данных хранятся пути к файлам в CDN.
Как устранить неполадки такого рода?
- Просмотрите журнал консоли браузера.
- Перейдите по URL-адресу мультимедиа непосредственно из браузера. Посмотрите, что вы получите. Если он пустой, что-то не так с вашим кодом поиска.
- В инструментах разработки в браузере посмотрите на вкладку Сеть (в Google Chrome). Найдите медиа-объект и изучите, что происходит.
Комментарии:
1. Действительно хороший ответ. Я пытался пока избегать gridfs, но это выглядит довольно понятно. Спасибо. Однако у меня есть несколько вопросов. Я предполагаю, что мне нужно сделать ajax-запрос на стороне клиента. если да, то что мне указать для расположения файла
xhttp.open("GET", "file location", true);
и так ли я указываю тип содержимого?xhttp.setRequestHeader("Content-type", "audio/mpeg");
2.
src
Атрибут в теге audio приведет к тому, что браузер получит ваш аудиофайл без необходимости в каком-либо сложном ajax. На вашем месте я бы сначала заставил это сработать.3. Итак, я пытался заставить это работать, но у меня не получается. Я немного обновил его, чтобы он соответствовал моему существующему коду. Пожалуйста, взгляните. Я обновил свой вопрос. Я думаю, что ошибка в этой строке ` const db = new MongoClient. Db (‘песни’, новый MongoClient. Сервер («localhost», 27017));` . Имя моей базы данных —
songs
. и имя коллекции —song
. Я не понимаю, как выполняется поиск в коллекции, просто введя имя базы данных.4. Прочитайте материал о GridFS. Обратите внимание, что у него есть своя собственная схема индексации. Объекты, которые вы извлекаете с помощью GridFS, должны быть помещены туда тем же способом. Вот почему я упомянул
mongofiles
. Вы можете заменить приведенный мной пример кода для перехода на Mongo своим кодом, который работает.5. В вашей ссылке mongofiles нет word. Не могли бы вы, пожалуйста, обновить его?
Ответ №2:
Я думаю, что то, что вы ищете, — это поток, чтобы вы могли передавать данные с сервера на веб-страницу напрямую, не сохраняя их. Node js поставляется с этой функциональностью, подробнее об этом из документации здесь https://nodejs.org/api/stream.html