Upload API mit NextJS und Azure Portal funktioniert nicht?
Hallo, ich bekomme wenn ich Videos über die API in Azure Portal hochlade immer eine Fehlermeldung. Manchmale sieht sie so aus:
Parsed files: {
videoFile: [
PersistentFile {
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
lastModifiedDate: 2024-12-17T10:12:37.964Z,
filepath: 'C:\\Users\\thoma\\AppData\\Local\\Temp\\19612948a7cd7d81f78632e00.mp4',
newFilename: '19612948a7cd7d81f78632e00.mp4',
originalFilename: 'sample-2.mp4',
mimetype: 'video/mp4',
hashAlgorithm: false,
size: 30424618,
_writeStream: [WriteStream],
hash: null,
[Symbol(shapeMode)]: false,
[Symbol(kCapture)]: false
}
]
}
Manchmal (gefühlt oft bei kleineren Dateien) funktioniert es auch der Log sieht dann so aus:
Uploading file from path: C:\Users\thoma\AppData\Local\Temp\19612948a7cd7d81f78632e00.mp4
Request timed out!
File uploaded to Azure successfully: sample-2.mp4
Hier lade ich noch den API Code hoch:
import { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } from '@azure/storage-blob';
import formidable from 'formidable';
import fs from 'fs/promises';
import { v4 as uuidv4 } from 'uuid';
export const config = {
api: {
bodyParser: false, // Disable default body parsing for file uploads
},
};
// Azure Storage connection string
const AZURE_STORAGE_CONNECTION_STRING =
'DefaultEndpointsProtocol=https;AccountName=innowesovideos;AccountKey=uyJz3dlCW/hd+t3Y48pSfuk1Q+pV63S1Hs48uvGIJW3ubaO/ngtSMrzoKRvBE4so7MP9zz73uaLl+AStwmS6EA==;EndpointSuffix=core.windows.net';
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Only POST requests are allowed' });
}
let filePath = ''; // Variable to track the file path for cleanup
try {
// Set a timeout to prevent stalls
const timeout = setTimeout(() => {
console.error('Request timed out!');
if (!res.writableEnded) {
res.status(504).json({ message: 'Request timed out. Please try again.' });
}
}, 15000); // 15-second timeout
// Initialize formidable for file parsing
const form = formidable({
keepExtensions: true, // Keep file extensions
maxFileSize: 5000 * 1024 * 1024,
});
console.log('New filesize')
// Parse the incoming form data
const { files } = await new Promise((resolve, reject) => {
form.parse(req, (err, fields, files) => {
if (err) {
console.error('Error parsing form:', err);
reject(err);
} else {
resolve({ fields, files });
}
});
});
console.log('Parsed files:', files);
// Normalize videoFile input (handle single and multiple files)
const fileData = Array.isArray(files.videoFile) ? files.videoFile[0] : files.videoFile;
// Validate file presence and format
if (!fileData || !fileData.filepath) {
throw new Error('No video file provided.');
}
filePath = fileData.filepath;
if (!filePath) throw new Error('No valid file path found.');
if (fileData.mimetype !== 'video/mp4') throw new Error('Only MP4 files are allowed.');
console.log('Uploading file from path:', filePath);
// Generate a unique file name for Azure Blob Storage
const fileName = fileData.originalFilename || `${uuidv4()}.mp4`;
// Load the file as a buffer
const fileBuffer = await fs.readFile(filePath);
// Initialize Azure Blob Storage Client
const blobServiceClient = BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
const containerClient = blobServiceClient.getContainerClient('videos');
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
// Upload the file to Azure Blob Storage
await blockBlobClient.uploadData(fileBuffer, {
blobHTTPHeaders: { blobContentType: 'video/mp4' },
});
// Generate a SAS token for the uploaded file
const sasToken = generateBlobSASQueryParameters(
{
containerName: 'videos',
blobName: fileName,
permissions: BlobSASPermissions.parse('r'), // Read permissions
startsOn: new Date(),
expiresOn: new Date(new Date().valueOf() + 3600 * 1000), // Token valid for 1 hour
},
blobServiceClient.credential
).toString();
const videoUrl = `${blockBlobClient.url}?${sasToken}`;
clearTimeout(timeout);
return res.status(200).json({ message: 'Video uploaded successfully', videoUrl });
} catch (error) {
console.error('Error during upload:', error.message);
return res.status(500).json({ message: 'File upload failed', error: error.message });
} finally {
if (filePath) {
try {
await fs.unlink(filePath);
console.log(`Temporary file deleted: ${filePath}`);
} catch (cleanupErr) {
console.error(`Failed to delete temporary file: ${filePath}`, cleanupErr);
}
}
}
}
Danke!
Der erste Codeblock zeigt soweit nur eine deiner Zwischenausgaben. Hast du vergessen, Logausgaben mit anzugeben?
Uploading file from path: C:\Users\thoma\AppData\Local\Temp\19612948a7cd7d81f78632e00.mp4
Request timed out!
Danach kommt nur noch das Uploading und der Timeout...
1 Antwort
Ich kann aus deinen Angaben heraus noch kein wirkliches Fehlerverhalten herauslesen.
Diese Ausgabe:
Parsed files: {
(...)
stammt von deiner Konsolenausgabe hier:
console.log('Parsed files:', files);
und der Timeout wird explizit von deinem Skript fabriziert.
const timeout = setTimeout(() => {
console.error('Request timed out!');
Bei größeren Dateien ist es nicht verwunderlich. Vielleicht setzt du einfach einmal den Timeout höher. Beispielsweise auf 2-5 Minuten statt nur 15 Sekunden.
Einen Hinweis, dass der Upload gescheitert wäre, sehe ich allerdings nicht. Die Ausgaben
Uploading file from path: C:\Users\thoma\AppData\Local\Temp\19612948a7cd7d81f78632e00.mp4
(...)
File uploaded to Azure successfully: sample-2.mp4
deuten auf einen erfolgreichen Upload hin.
Das Objekt, welches du als zweites Argument an uploadData übergibst, kann einen Callback (onProgress) aufnehmen. Das Event-Objekt, welches du dabei empfängst, beinhaltet die bereits geladenen Bytes.
Kann ich irgendwie den Stand des Uploads abfragen um zu sehen wie viel Prozent der Upload fortgeschritten ist?