AngularJS表单上传视频至API失败:TOP_ASSET显示为{}
Hey there, let's figure out why your video upload is showing up as {} for the TOP_ASSET field in the network panel. I’ve gone through your code and found a few critical issues that are causing this problem—let’s break them down and fix them step by step.
Key Issues in Your Code
1. You’re Converting the File Object to JSON (Which Breaks It)
In your code, you’re taking the video File object and converting it to JSON with:
var myFile = jQuery.parseJSON(JSON.stringify($scope.video));
File objects are special browser-native objects that can’t be properly serialized to JSON. When you do this, you lose all the binary file data, which is why TOP_ASSET ends up as an empty object {} in the request. You should use the original File object directly instead of converting it.
2. You’re Sending a Regular JSON Request Instead of FormData
Uploading binary files (like videos) can’t be done with a standard JSON request—you need to use FormData instead. Your current approach sends a JSON payload, which can’t handle the video’s binary data. Even though your image works with base64 encoding, videos are usually too large for base64 (it increases file size by ~33%), so using FormData is the right approach for both files.
3. Unreliable Timing with $timeout
You’re using a hardcoded 3-second $timeout to wait for the FileReader to finish encoding the image. This is risky—if the image takes longer than 3 seconds to encode, your request will send incomplete data. Instead, we should use Promises to wait for the FileReader to actually finish before sending the request.
Fixed Code Implementation
Here’s the revised version of your uploadFile function with these issues addressed:
$scope.uploadFile = function (callback, e) { $scope.video = document.getElementById('fileVideo').files[0]; if (!$scope.video) { console.log("No video file selected"); return; } // Check video file size first if ($scope.video.size >= 209715200) { // 200MB limit console.log("File terlalu besar"); return; } // Handle image encoding with Promises const imageEncodePromise = new Promise((resolve) => { let encodeTemp = ""; // Assuming file2 is the image uploader angular.forEach($scope.uploader1.queue, function (value, index) { const reader = new FileReader(); reader.readAsDataURL(value._file); reader.onload = function (ev) { const base64 = ev.target.result.substring(ev.target.result.indexOf(',') + 1); encodeTemp += base64 + ' '; // Resolve when all images are processed if (index === $scope.uploader1.queue.length - 1) { resolve(encodeTemp.trim()); } }; }); // If no images are selected, resolve empty string if ($scope.uploader1.queue.length === 0) { resolve(""); } }); // Wait for image encoding to finish, then send request imageEncodePromise.then((encodedImage) => { // Create FormData for the request const fd = new FormData(); fd.append('TERMINAL_ID', $scope.getTerminalByID); fd.append('TOP_ASSET', $scope.video); // Use original File object fd.append('BOTTOM_ASSET', encodedImage); fd.append('DESCRIPTION', $scope.description); // Send the FormData via POST callApi.callPostApi('uploadUpdateTerminalAsset', fd, { headers: { 'Content-Type': undefined } // Let browser set correct Content-Type }).then(function (response) { if (response.STATUS === "failed") { console.log("Upload failed:", response); } else { // $state.go('restricted.dashboard'); console.log("Upload successful!"); if (callback) callback(); } }).catch(function(error) { console.error("Error during upload:", error); }); }); };
Additional Notes
- FormData Headers: When sending FormData, make sure your
callPostApifunction sets theContent-Typeheader toundefined(or lets the browser set it automatically). This ensures the browser adds the correctmultipart/form-databoundary, which is required for file uploads. - FileReader Cleanup: I removed the global
$scope.reader1and used a local variable inside the loop to avoid overwriting the reader instance for multiple files. - Error Handling: Added checks for missing video files and proper error catching in the API call.
This should fix the issue where TOP_ASSET shows up as {}—now the actual video file will be sent in the request, and the image encoding will reliably complete before the request is sent.
内容的提问来源于stack exchange,提问作者William

