#javascript #node.js #express #fetch
Вопрос:
Я использую NodeJS w/ Express для создания веб-приложения, которое записывает ваш звук с помощью библиотеки VMSG и отправляет звук большого двоичного объекта в мою файловую систему с помощью HTTP-запросов и многопоточности. Он также добавляет этот экземпляр записи в базу данных MongoDB.
У меня проблема с командой fetch. Это не сработает, если я не отправлю предупреждение сразу после извлечения. Способ, которым я его настроил, заключается в том, что у меня есть мое основное экспресс-приложение (index.js), и маршрутизатор к каталогу /recordingsDirectory (recordings.js) , которая является конечной точкой для обработки сообщений. Моя основная индексная HTML-страница использует рули и использует отдельный JS-скрипт (recorder.js) для 1) использования библиотеки VMSG и 2) получения ЗАПИСИ в каталог /Recordings, как только кто-то отправит аудиофайл с именем и присутствующим аудиоблоком. Вот где я застрял. Я могу принести в recorder.js с предупреждающей строкой после выборки, но я не могу получить выборку в конце блока else if сам по себе. Я бы хотел сделать это без этого, так как предупреждение уродливое. Решение, которое я пробовал, заключается в том, что я попытался сделать функцию onsubmit асинхронной и ожидающей выборки, так как я думал, что, возможно, она ждет обещания, но это не сработало.
Вот файлы. Я прокомментировал КРИТИЧЕСКИЕ и СВЕРХКРИТИЧНЫЕ строки кода, которые вы должны проверить, и я думаю, в чем заключаются проблемы:
index.js
const express = require('express')
const handlebars = require('express-handlebars')
const path = require('path')
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const xhr = new XMLHttpRequest()
const db = require('./db')
const app = express()
const PORT = process.env.PORT || 8000
app.set('view engine', 'hbs')
app.engine('hbs', handlebars({
layoutsDir: path.join(__dirname, 'views', 'layouts'),
extname: 'hbs',
defaultLayout: 'index',
partialsDir: path.join(__dirname, 'views', 'partials'),
}))
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use((err, req, res, next) => {
if (err instanceof SyntaxError amp;amp; err.status === 400 amp;amp; 'body' in err) {
return res.status(400).send({ status: 404, message: err.message })
}
next()
})
app.get('/', (req, res) => {
res.render('main', {
title: 'Main Page'
})
})
app.get('/recordings', (req, res) => {
var database = db.get().db('AudioJungle')
database.collection('recordings').find().sort({ "date": -1 }).toArray(function(err, docs) {
res.render('recordings', {
title: 'Recordings',
recordings: docs
})
})
})
// CRITICAL
app.use('/recordingsDirectory', require('./recordings/recordings'))
app.use(express.static('public'))
app.use('/scripts', express.static(path.join(__dirname, 'node_modules', 'vmsg')))
db.connect(function(err) {
if (err) {
console.log('Unable to connect to Mongo.')
process.exit(1)
} else {
app.listen(PORT, () => console.log(`Listening on Port: ${PORT}`))
}
})
process.on('SIGINT', function() {
db.close(function () {
console.log('Disconnected on app termination');
process.exit(0);
});
});
app.use((req, res, next) => {
res.status(404).send({
status: 404,
error: 'Not found'
})
})
recordings.js (Aka the /recordingsDirectory endpoint for a fetch POST)
const express = require('express')
const router = express.Router()
const multer = require('multer')
const fs = require('fs-extra')
const db = require('../db')
const { ObjectId } = require('bson')
const moment = require('moment')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, callback) => {
let path = './public/uploads'
fs.mkdirsSync(path)
callback(null, path)
},
filename: (req, file, callback) => {
createRecording(req).then((id) => {
var file_name = id '.mp3'
callback(null, file_name)
})
}
})
})
var type = upload.single('audio-file')
// CRITICAL
router.post('/', type, (req, res) => {
console.log('made it')
res.status(200)
res.send('OK')
})
router.delete('/delete', (req, res) => {
deleteRecording(req.body._id).then((dbResponse) => {
if (dbResponse == null || dbResponse == undefined) {
res.status(400).json({ msg: 'ID already deleted' })
} else {
res.status(200)
}
})
})
router.get('/', (req, res) => {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
recordings.findOne({"_id": ObjectId(req.query.id)}, function(err, result) {
if (err) throw err
if (result == null || result == undefined) {
return res.status(400).json({
status: 404,
error: 'Recording no longer in the database'
})
}
res.status(200)
res.json({
name: result.name,
date: result.date
})
})
})
async function createRecording(req) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioObject = {
name: req.body.name,
date: moment().format('MMMM Do YYYY, h:mm:ss a')
}
var dbResponse = await recordings.insertOne(audioObject)
return dbResponse.insertedId
}
async function deleteRecording(id) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioToDelete = {
_id: ObjectId(id)
}
var deleteResult = await recordings.deleteOne(audioToDelete)
return deleteResult
}
module.exports = router
And below is the Script the audio and name and tries to Fetch (where I need the alert for it to actually process into the /recordingsdirectory)
recorder.js
import { record } from "/scripts/vmsg.js";
let recordButton = document.getElementById("record");
var blobObj = null
recordButton.onclick = function() {
record({wasmURL: "/scripts/vmsg.wasm"}).then(blob => {
blobObj = blob
var tag = document.createElement("p")
tag.id="finishedRecording"
var text = document.createTextNode("Audio File Recorded")
tag.appendChild(text)
var element = document.getElementById("box")
element.appendChild(tag)
document.getElementById('box').appendChild(a)
})
}
let form = document.getElementById('mp3Form');
form.addEventListener("submit", submitAudio)
function submitAudio() {
var fileName = form.elements[0].value
if (fileName == "") {
alert('Please enter a name for your file')
} else if (blobObj != null) {
// CRITICAL
// SUPER CRITICAL WHERE FETCH DOESN'T WORK UNLESS I PUT AN ALERT AT THE END
const formData = new FormData()
formData.append('name', fileName)
formData.append('audio-file', blobObj)
const options = {
method: 'POST',
body: formData
}
fetch('/recordingsDirectory', options);
// If I comment an alert here, /recordingsDirectory will process the post since it console.logs 'made it'
} else {
alert('Record some Audio to upload')
}
}
Вот моя файловая система.
Кроме того, я хотел бы отметить, что функция извлечения работает должным образом на моем ПК с Windows без необходимости добавлять предупреждение, но она не работает без предупреждения на моем MacBook. Если кто-нибудь обнаружит исправление или ошибку в том, как я делаю это, пожалуйста, дайте мне знать. Я застрял на этой проблеме уже целый день. Огромное спасибо!
Комментарии:
1. Вам необходимо запретить процесс отправки формы по умолчанию. Предупреждение просто блокирует его
2. @charlietfl Милая! Это решило проблему, но могу ли я спросить, что именно делает preventDefault для решения этой проблемы? Я совершенно не понимаю, как это все исправляет.
3. Когда вы добавляете прослушиватель событий отправки, он запускается до того, как произойдет окончательная отправка, если вы не предотвратите использование по умолчанию. Браузер отправит форму внутренне по
action
URL-адресу формы или текущему URL-адресу, если никаких действий не существует. Предотвращение остановок по умолчанию, которые