I am working on a React project where I sell courses, and when I try to upload a video file larger than 1 GB, the upload process always stops midway. However, other files smaller than that upload without any issues.
I’m not using AWS or any other services; I’m trying to store the videos directly on my backend server (Cyber Panel).
How can I fix this? I’m still learning about this topic.
here is my code in backend
export const uploadMultiplePelatihanVideo = async (req, res) => {
// if (!req.files || !req.files.files) {
// return res.status(400).json({ msg: "Tidak ada file yang diunggah." });
// }
const files = Array.isArray(req.files.files) ? req.files.files : [req.files.files];
const allowedExt = [".mp4", ".avi", ".mkv"]; // Format video yang diizinkan
const maxFileSize = 10000000000; // Batas ukuran file video 10000 MB
const uploadedVideos = [];
const title = req.body.title || "Tanpa Judul";
try {
const pelatihan = await Pelatihan.findOne({
where: { pelatihanId: req.params.pelatihanId }
});
if (!pelatihan) {
return res.status(404).json({ msg: "Pelatihan tidak ditemukan." });
}
// Loop melalui setiap file video yang diunggah
for (const file of files) {
const fileSize = file.data.length;
const ext = path.extname(file.name);
const fileName = uuidv4() + ext;
const url = `${req.protocol}://${req.get("host")}/videos/pelatihan/${fileName}`;
// Validasi ekstensi dan ukuran file
if (!allowedExt.includes(ext.toLowerCase())) {
return res.status(422).json({ msg: "Silakan unggah file video saja." });
}
if (fileSize > maxFileSize) {
return res.status(422).json({ msg: `Ukuran file ${file.name} terlalu besar, maksimal 1000 MB.` });
}
// Pindahkan file video baru ke direktori
await file.mv(`public/videos/pelatihan/${fileName}`, async (err) => {
if (err) {
return res.status(500).json({ msg: "Gagal memindahkan file video." });
}
// Simpan informasi video ke database
const video = await VideoPel.create({
pelatihanId: pelatihan.pelatihanId,
urlVideo: url,
title, // Judul video dari body atau default
deskripsi: req.body.deskripsi || null, // Deskripsi dari body atau null
});
uploadedVideos.push({
fileName,
url,
videoId: video.videoPelId,
});
});
}
// Mengirimkan response setelah semua video berhasil diunggah
res.status(200).json({
msg: "Video pelatihan berhasil diunggah.",
uploadedVideos, // Mengembalikan daftar video yang berhasil diunggah
});
} catch (error) {
console.error("Error uploading video:", error);
res.status(500).json({ msg: "Terjadi kesalahan pada server." });
}
};
and in the frontend
export const uploadMultiplePelatihanVideo = async (files, id, onUploadProgress) => {
const token = sessionStorage.getItem("authToken"); // Mendapatkan token otentikasi dari sessionStorage
try {
const response = await axios.post(
`${API_URL}/pelatihan/${id}/upload-full-video`,
files,
{
headers: {
Authorization: `Bearer ${token}`, // Menyertakan token otentikasi
"Content-Type": "multipart/form-data", // Mengatur tipe konten
},
onUploadProgress: onUploadProgress,
timeout: 0, // Set timeout to 0 (no timeout)
}
);
// Menampilkan notifikasi sukses menggunakan SweetAlert2
Swal.fire({
icon: "success",
title: "Berhasil mengupload video",
text: "Semua video telah berhasil diupload ke pelatihan.",
});
return response.data; // Mengembalikan data respons dari server
} catch (error) {
// Menampilkan notifikasi error menggunakan SweetAlert2
Swal.fire({
icon: "error",
title: "Gagal mengupload video",
text: error.response?.data?.msg || "Terjadi kesalahan, silakan coba lagi.",
});
throw error; // Lempar error agar bisa ditangani di tempat lain jika diperlukan
}
};
function editPelatihan(){
const [previewVideos, setPreviewVideos] = useState([]);
const [uploadProgress, setUploadProgress] = useState(0);
const handleMultipleVideoSubmit = async (e) => {
e.preventDefault();
const { videoPel, title } = formVideo;
if (videoPel.length === 0) {
Swal.fire({
icon: "warning",
title: "Video pelatihan tidak ada",
text: "Silakan unggah video pelatihan terlebih dahulu.",
});
return;
}
try {
const videoFormData = new FormData();
videoPel.forEach(file => videoFormData.append('files', file));
videoFormData.append('title', title);
await uploadMultiplePelatihanVideo(videoFormData, pelatihanId, (progressEvent) => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
setUploadProgress(percentCompleted);
});
Swal.fire({
icon: "success",
title: "Video pelatihan berhasil diunggah",
text: "Semua video pelatihan telah berhasil ditambahkan ke pelatihan.",
});
setFormVideo({
videoPel: [],
title: "", // Reset title setelah upload
});
setPreviewVideos([]);
setUploadProgress(0); // Reset progress after upload
} catch (error) {
Swal.fire({
icon: "error",
title: "Gagal mengunggah video pelatihan",
text: "Terjadi kesalahan saat mengunggah video pelatihan.",
});
}
};
return (
<form className="space-y-4 mt-4">
{/* Upload Video Pelatihan */}
<div>
<label htmlFor="videoPel" className="block text-sm font-medium text-gray-300">
Upload Video Pelatihan
</label>
<input
type="file"
id="videoPel"
name="videoPel"
accept="video/*"
multiple
onChange={handleChange}
className="mt-1 block w-full text-sm border border-gray-700 rounded-lg cursor-pointer text-gray-400 focus:outline-none bg-gray-700 placeholder-gray-400"
/>
<input
type="text"
id="title"
name="title"
placeholder="Masukkan judul video"
value={formVideo.title}
onChange={handleChange}
className="mt-1 block w-full text-sm border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
{previewVideos.length > 0 && (
<div className="mt-2">
{previewVideos.map((videoUrl, index) => (
<video key={index} src={videoUrl} controls className="mt-2 w-full max-h-64 object-cover rounded-md" />
))}
</div>
)}
<button
onClick={handleMultipleVideoSubmit}
className="mt-2 bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-lg"
>
Unggah Video Pelatihan
</button>
</div>
<div className="mt-4">
{uploadProgress > 0 && uploadProgress < 100 && (
<div>
<progress value={uploadProgress} max="100" className="w-full" />
<span>{uploadProgress}%</span>
</div>
)}
</div>
</form>
)
}
Stuck like this: Screenshot
upload-full-video(failed)net::ERR_CONNECTION_CLOSEDxhr
Server side logs: No files uploaded.
The server has no upload limits.