JavaScript与Django集成:实现前端录制视频文件到后端存储的教程

JavaScript与Django集成:实现前端录制视频文件到后端存储的教程

本教程详细指导如何在JavaScript前端录制视频后,通过Fetch API将其上传至Django后端进行文件系统存储和数据库关联。文章涵盖了前端视频数据处理、csrf令牌管理以及django视图层接收文件并保存的完整流程,旨在帮助开发者实现视频录制与持久化存储的无缝集成。

在现代web应用中,用户生成内容的场景日益增多,其中视频录制与上传是常见需求。本教程将深入探讨如何将前端javascript录制的视频文件,通过异步请求(fetch api)安全有效地传输至django后端,实现文件的持久化存储于文件系统,并将其关联信息记录到数据库中。与传统表单提交方式不同,我们采用更灵活的api驱动方法,优化用户体验并提升开发效率。

1. 前端视频录制与数据封装

首先,我们依赖JavaScript的MediaDevices API(getUserMedia)进行视频流获取,并使用MediaRecorder API进行录制。录制完成后,视频数据以Blob(二进制大对象)的形式存储在recordedBlobs数组中。为了将此Blob发送到服务器,我们需要将其封装为FormData对象。

1.1 录制流程回顾

前端html结构包含video元素用于显示摄像头预览和录制回放,以及控制按钮(开始、录制、播放、下载)。JavaScript代码负责:

  • 通过navigator.mediaDevices.getUserMedia获取摄像头和麦克风权限及流。
  • 实例化MediaRecorder对象,并监听ondataavailable事件收集视频数据块。
  • 在stopRecording时,recordedBlobs数组包含了完整的视频数据。

1.2 封装视频数据为FormData

当用户点击“下载”按钮时,除了传统的客户端下载逻辑外,我们还需要触发上传至后端的动作。核心在于将recordedBlobs合并成一个Blob,然后将其转换为File对象并添加到FormData中。

 // ... (保留原有的JavaScript录制逻辑,例如mediaRecorder、recordedBlobs等)  const errorMsgElement = document.querySelector('span#errorMsg'); const recordedVideo = document.querySelector('video#recorded'); const recordButton = document.querySelector('button#record'); const playButton = document.querySelector('button#play'); const downloadButton = document.querySelector('button#download');  // 获取CSRF Token的辅助函数 function getCookie(name) {   const value = `; ${document.cookie}`;   const parts = value.split(`; ${name}=`);   if (parts.length === 2) return parts.pop().split(';').shift(); }  // 上传函数:负责将FormData发送到Django后端 async function upload(formData) {   try {     // 这里的URL '/video-app' 需与Django的urls.py配置保持一致     const response = await fetch("/video-app", {       method: "POST",       headers: {         "X-CSRFToken": getCookie('csrftoken'), // 附带CSRF Token,确保Django安全认证       },       body: formData, // 发送FormData对象,Fetch API会自动设置Content-Type为multipart/form-data     });     const result = await response.JSon(); // 解析后端返回的json响应     console.log("上传响应:", result);     // 根据后端返回的result处理,例如显示成功或失败消息     if (result.error_code === 0) {         alert('视频上传成功!');     } else {         alert('视频上传失败: ' + result.message);     }   } catch (error) {     console.error("上传错误:", error);     alert('视频上传过程中发生错误!');   } }  // 修改下载按钮的点击事件,增加上传逻辑 downloadButton.addEventListener('click', () => {   // 将录制的Blob数据合并为一个完整的MP4视频Blob   const blob = new Blob(recordedBlobs, {type: 'video/mp4'});    // 1. 上传到服务器   const formData = new FormData();   // 将Blob转换为File对象,命名为'my-interview.mp4',并作为'video'字段添加到FormData   formData.append("video", new File([blob], 'my-interview.mp4'));   upload(formData); // 调用上传函数    // 2. 客户端下载(如果不需要客户端下载,可以移除以下代码)   const url = window.URL.createObjectURL(blob);   const a = document.createElement('a');   a.style.display = 'none';   a.href = url;   a.download = 'w3-coder-recorder-test.mp4'; // 客户端下载的文件名   document.body.appendChild(a);   a.click();   setTimeout(() => {     document.body.removeChild(a);     window.URL.revokeObjectURL(url);   }, 100); });  // ... (保留原有的start/stop Recording, play, handleSuccess, init等函数) // 确保MediaRecorder的ondataavailable和onstop事件处理逻辑正确 function handleDataAvailable(event) {   console.log('handleDataAvailable', event);   if (event.data && event.data.size > 0) {     recordedBlobs.push(event.data);   } }  function startRecording() {   recordedBlobs = [];   let options = {mimeType: 'video/webm;codecs=vp9,opus'};   try {     mediaRecorder = new MediaRecorder(window.stream, options);   } catch (e) {     console.error('Exception while creating MediaRecorder:', e);     errorMsgElement.innerHTML = `Exception while creating MediaRecorder: ${JSON.stringify(e)}`;     return;   }   recordButton.textContent = 'Stop Recording';   playButton.disabled = true;   downloadButton.disabled = true;   mediaRecorder.onstop = (event) => {     console.log('Recorder stopped: ', event);     console.log('Recorded Blobs: ', recordedBlobs);   };   mediaRecorder.ondataavailable = handleDataAvailable;   mediaRecorder.start(); }  function stopRecording() {   mediaRecorder.stop();   recordButton.textContent = 'Record'; // 停止后将按钮文本改回“Record”   playButton.disabled = false;   downloadButton.disabled = false; }

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享