When I try to upload, I get the following error:
Error code:1363030,
msg: Your video upload timed out before it could be completed. This is probably because of a slow network connection or because the video you're trying to upload is too large. Please try again.
I'm using Facebook Javascript SDK 2.5.
What am I missing or wrong?
<script>
var files;
var fileData = '';
function handleFileSelect(evt) {
files = evt.target.files; // FileList object
var input = evt.target;
var reader = new FileReader();
reader.onload = function (e) {
fileData = e.target.result;
};
reader.readAsDataURL(input.files[0]);
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
output.push('<li class="list-group-item">', escape(f.name), '(', f.type || 'n/a', ') - ',
f.size, ' bytes','</li>');
}
document.getElementById('list').innerHTML = output.join('');
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
$(document).ready(function()
{
$("#upload").click(function(){
var token = $('#token').val();
FB.api(
"/me/videos",
"POST",
{
"access_token" : token,
"title" : 'test',
"source": fileData
},
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
})
});
</script>
here is the sample site
Just hit this in Node.js. This Facebook error occurs if you don't specify the content type and file name of the attached file (i.e. if you pass it as an inline field value, not as an attached file).
Not sure how to do it via FB.api, but with request-promise module (and ES7 async functions via Babel) it looks like this:
import request from 'request-promise'
async function uploadVideoToFacebook (buf) {
let url = 'https://graph-video.facebook.com/v2.5/' + pageId + '/videos?access_token=' + pageToken
let formData = {
title: 'Video title',
description: 'Timeline message...',
source: {
value: buf,
options: {
filename: 'video.mp4',
contentType: 'video/mp4'
}
}
}
return await request({ method: 'POST', url, formData })
}
and with XMLHttpRequest on the client-side you would do something like:
var blob = new Blob(videoDataHere, { type: 'video/mp4' })
var formData = new FormData();
formData.append('source', blob);
formData.append('message', 'Spartan Overlay');
var ajax = new XMLHttpRequest()
ajax.onreadystatechange = ...
ajax.open('POST', 'https://graph.facebook.com/' + userId + '/videos?access_token=' + accessToken, true)
ajax.send(formData)
Related
Thanks for reading my question. I am working on the google drive api and can upload files from a text blob to the google drive. However, I need to add the folder ID manually and for users to use this and not get an error since they are trying to upload it into my folder. How can I create or just get a folder ID - maybe even upload to the root GDrive directory ? Any tips would be helpful.
Thanks
// Global vars
const SCOPE = 'https://www.googleapis.com/auth/drive.file';
const gdResponse = document.querySelector('#response');
const login = document.querySelector('#login');
const authStatus = document.querySelector('#auth-status');
const textWrap = document.querySelector('.textWrapper');
const addFolder = document.querySelector('#createFolder');
const uploadBtn = document.querySelector('#uploadFile');
// Save Button and Function
uploadBtn.addEventListener('click', uploadFile);
window.addEventListener('load', () => {
console.log('Loading init when page loads');
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
});
function initClient() {
const discoveryUrl =
'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client
.init({
apiKey: 'My-API-Key',
clientId:
'My-Client-ID',
discoveryDocs: [discoveryUrl],
scope: SCOPE,
})
.then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Actual upload of the file to GDrive
function uploadFile() {
let accessToken = gapi.auth.getToken().access_token; // Google Drive API Access Token
console.log('Upload Blob - Access Token: ' + accessToken);
let fileContent = document.querySelector('#content').value; // As a sample, upload a text file.
console.log('File Should Contain : ' + fileContent);
let file = new Blob([fileContent], { type: 'application/pdf' });
let metadata = {
name: 'Background Sync ' + date, // Filename
mimeType: 'text/plain', // mimeType at Google Drive
// For Testing Purpose you can change this File ID to a folder in your Google Drive
parents: ['Manually-entered-Folder-ID'], // Folder ID in Google Drive
// I'd like to have this automatically filled with a users folder ID
};
let form = new FormData();
form.append(
'metadata',
new Blob([JSON.stringify(metadata)], { type: 'application/json' })
);
form.append('file', file);
let xhr = new XMLHttpRequest();
xhr.open(
'post',
'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id'
);
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.responseType = 'json';
xhr.onload = () => {
console.log(
'Upload Successful to GDrive: File ID Returned - ' + xhr.response.id
); // Retrieve uploaded file ID.
gdResponse.innerHTML =
'Uploaded File. File Response ID : ' + xhr.response.id;
};
xhr.send(form);
}
I didn't include some of the unrelated stuff. I have something like this for the uploading of a folder and it's not working unsurprisingly.
function createFolder() {
var fileMetadata = {
name: 'WordQ-Backups',
mimeType: 'application/vnd.google-apps.folder',
};
drive.files.create(
{
resource: fileMetadata,
fields: 'id',
},
function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('Folder Id: ', file.id);
}
}
);
}
I believe your goal as follows.
You want to upload a file to the root folder or the created new folder.
For this, how about the following modification patterns?
Pattern 1:
When you want to put the file to the root folder, please try the following modification.
From:
parents: ['Manually-entered-Folder-ID'],
To:
parents: ['root'],
or, please remove parents: ['Manually-entered-Folder-ID'],. By this, the file is created to the root folder.
Pattern 2:
When you want to create new folder and put the file to the created folder, please try the following modification. In your script, unfortunately, I'm not sure about drive in createFolder() from your question. So I cannot understand about the issue of your createFolder(). So in this pattern, the folder is created with XMLHttpRequest.
Modified script:
function createFile(accessToken, folderId) {
console.log('File Should Contain : ' + fileContent);
let fileContent = document.querySelector('#content').value;
console.log('File Should Contain : ' + fileContent);
let file = new Blob([fileContent], { type: 'application/pdf' });
let metadata = {
name: 'Background Sync ' + date,
mimeType: 'text/plain',
parents: [folderId], // <--- Modified
};
let form = new FormData();
form.append(
'metadata',
new Blob([JSON.stringify(metadata)], { type: 'application/json' })
);
form.append('file', file);
let xhr = new XMLHttpRequest();
xhr.open(
'post',
'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id'
);
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.responseType = 'json';
xhr.onload = () => {
console.log(
'Upload Successful to GDrive: File ID Returned - ' + xhr.response.id
);
gdResponse.innerHTML =
'Uploaded File. File Response ID : ' + xhr.response.id;
};
xhr.send(form);
}
function createFolder(accessToken) {
const folderName = "sample"; // <--- Please set the folder name.
let metadata = {
name: folderName,
mimeType: 'application/vnd.google-apps.folder'
};
let xhr = new XMLHttpRequest();
xhr.open('post', 'https://www.googleapis.com/drive/v3/files?fields=id');
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'json';
xhr.onload = () => {
const folderId = xhr.response.id;
console.log(folderId);
createFile(accessToken, folderId);
};
xhr.send(JSON.stringify(metadata));
}
// At first, this function is run.
function uploadFile() {
let accessToken = gapi.auth.getToken().access_token;
createFolder(accessToken);
}
Reference:
Files: create
I am working Angular SPA application.
I am using SP.js & SP.Requestor.js which is useful to upload the same but none seems to be working of Angular 4 App.
UploadFile(event: any) {
let fileList: FileList = event.target.files;
let fileName;
if (fileList.length != 0) {
this.getFileBuffer(fileList[0]).then(result => {
this.uploadFile(result, fileList[0].name, "POC").then(result => {
alert("added");
});
});
// this.fileUpload(fileList[0], "RetrievePOC", fileList[0].name);
}
}
getFileBuffer(file) {
return new Promise((resolve, reject) => {
var myReader: FileReader = new FileReader();
myReader.onload = function (e) {
resolve(myReader.result);
//resolve(e.target);
}
myReader.onerror = function (e) {
//deferred.reject(e.target.error);
}
//myReader.readAsArrayBuffer(file);
myReader.readAsBinaryString(file);
//resolve(file);
//return deferred.promise();
});
};
uploadFile(file, fileName, libraryName) {
return new Promise((resolve, reject) => {
// Construct the endpoint - The GetList method is available for SharePoint Online only.
//var serverRelativeUrlToFolder = "decodedurl='" + "/" + libraryName + "'";
var endpoint = this.siteUrl + "/_api/web/lists/getByTitle('POC')/Files/add('" + fileName + "')";
const headers = {
"accept": "application/json;odata=verbose",
"content-type": "application/json; odata=verbose",
};
//let fileData =this.convertDataBinaryString(file);
this.executeAsync(endpoint, file, headers).then(file => resolve(true)).catch(err => reject(err));
});
}
executeAsync(endPointUrl, data, requestHeaders) {
return new Promise((resolve, reject) => {
// using a utils function we would get the APP WEB url value and pass it into the constructor...
let executor = new SP.RequestExecutor(this.siteUrl);
// Send the request.
executor.executeAsync({
url: endPointUrl,
method: "POST",
body: data,
binaryStringRequestBody: true,
headers: requestHeaders,
success: offset => resolve(offset),
error: err => reject(alert(err.responseText))
});
});
}
Getting following error in executeAsync methond :
ErrorPage.PostMessage: Origin=https://localhost:44316,
Data={"command":"Query","postMessageId":"SP.RequestExecutor3","responseAvailable":false,"errorCode":-1007,"errorMessage":"Correlation
ID: e12d5a9e-b0d6-0000-745f-24b31dd971a6"}
vendor.js?v=T82_qgC1tKr4vAoag-4pr9ch_dUDSit3nEgaqP4H0Ec:12090 ERROR
Error: Uncaught (in promise): undefined
at resolvePromise (vendor.js?v=T82_qgC1tKr4vAoag-4pr9ch_dUDSit3nEgaqP4H0Ec:87020
)
We can use jQuery to upload file, here is a demo for your reference:
HTML:
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" type="text/javascript"></script>
<input id="getFile" type="file"/><br />
<input id="displayName" type="text" value="Enter a unique name" /><br />
<input id="addFileButton" type="button" value="Upload" onclick="uploadFile()"/>
JS code:
'use strict';
jQuery(document).ready(function () {
// Check for FileReader API (HTML5) support.
if (!window.FileReader) {
alert('This browser does not support the FileReader API.');
}
});
// Upload the file.
// You can upload files up to 2 GB with the REST API.
function uploadFile() {
// Define the folder path for this example.
var serverRelativeUrlToFolder = '/shared documents';
// Get test values from the file input and text input page controls.
var fileInput = jQuery('#getFile');
var newName = jQuery('#displayName').val();
// Get the server URL.
var serverUrl = _spPageContextInfo.webAbsoluteUrl;
// Initiate method calls using jQuery promises.
// Get the local file as an array buffer.
var getFile = getFileBuffer();
getFile.done(function (arrayBuffer) {
// Add the file to the SharePoint folder.
var addFile = addFileToFolder(arrayBuffer);
addFile.done(function (file, status, xhr) {
// Get the list item that corresponds to the uploaded file.
var getItem = getListItem(file.d.ListItemAllFields.__deferred.uri);
getItem.done(function (listItem, status, xhr) {
// Change the display name and title of the list item.
var changeItem = updateListItem(listItem.d.__metadata);
changeItem.done(function (data, status, xhr) {
alert('file uploaded and updated');
});
changeItem.fail(onError);
});
getItem.fail(onError);
});
addFile.fail(onError);
});
getFile.fail(onError);
// Get the local file as an array buffer.
function getFileBuffer() {
var deferred = jQuery.Deferred();
var reader = new FileReader();
reader.onloadend = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(fileInput[0].files[0]);
return deferred.promise();
}
// Add the file to the file collection in the Shared Documents folder.
function addFileToFolder(arrayBuffer) {
// Get the file name from the file input control on the page.
var parts = fileInput[0].value.split('\\');
var fileName = parts[parts.length - 1];
// Construct the endpoint.
var fileCollectionEndpoint = String.format(
"{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" +
"/add(overwrite=true, url='{2}')",
serverUrl, serverRelativeUrlToFolder, fileName);
// Send the request and return the response.
// This call returns the SharePoint file.
return jQuery.ajax({
url: fileCollectionEndpoint,
type: "POST",
data: arrayBuffer,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"content-length": arrayBuffer.byteLength
}
});
}
// Get the list item that corresponds to the file by calling the file's ListItemAllFields property.
function getListItem(fileListItemUri) {
// Send the request and return the response.
return jQuery.ajax({
url: fileListItemUri,
type: "GET",
headers: { "accept": "application/json;odata=verbose" }
});
}
// Change the display name and title of the list item.
function updateListItem(itemMetadata) {
// Define the list item changes. Use the FileLeafRef property to change the display name.
// For simplicity, also use the name as the title.
// The example gets the list item type from the item's metadata, but you can also get it from the
// ListItemEntityTypeFullName property of the list.
var body = String.format("{{'__metadata':{{'type':'{0}'}},'FileLeafRef':'{1}','Title':'{2}'}}",
itemMetadata.type, newName, newName);
// Send the request and return the promise.
// This call does not return response content from the server.
return jQuery.ajax({
url: itemMetadata.uri,
type: "POST",
data: body,
headers: {
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"content-type": "application/json;odata=verbose",
"content-length": body.length,
"IF-MATCH": itemMetadata.etag,
"X-HTTP-Method": "MERGE"
}
});
}
}
// Display error messages.
function onError(error) {
alert(error.responseText);
}
I have a front end Canvas that I transform into a png file that I need to POST to a third party vendor's api. It passes back to node as a base64 file and I decode it, but when I attempt the upload, it gives me the following error:
Problem processing POST request: no Content-Type specified
However, I am clearly specifying the content type in my POST call. My end goal is to upload the file to my vendor's API.
Here are the key front end aspects:
var canvasImage = document.getElementById("c");
var img = canvas.toDataURL({
multiplier: canvasMultiplier
});
var fileTime = Date.now();
var myFileName = $scope.productCode + fileTime;
$scope.filenameForVendor = myFileName;
var filename = $scope.filenameForVendor;
$http.post('/postVendor', { filename: filename, file: img }).success(function (data) {
console.log("Uploaded to Vendor");
Here is the backend POST:
app.post('/postVendor', function (req, res, next) {
var filename = req.body.filename;
var file = req.body.file;
fileBuffer = decodeBase64Image(file);
request({
url: "http://myvendorapi/ws/endpoint",
method: "POST",
headers: {
'contentType': fileBuffer.type
},
body: fileBuffer.data
}, function (error, response, body) {
console.log(response);
});
})
// Decode file for upload
function decodeBase64Image(dataString) {
var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/),
response = {};
if (matches.length !== 3) {
return new Error('Invalid input string');
}
response.type = matches[1];
response.data = new Buffer(matches[2], 'base64');
return response;
}
I can POST using AJAX on the front end, but because of CORS and the vendor blocking all but server side calls to the endpoints (and they don't have JSONP), I can't use this. They are allowing my IP through for testing purposes so only I can make this work from my machine:
var send = function (blob) {
var fileTime = Date.now();
var myFileName = $scope.productCode + fileTime;
$scope.filenameForVendor = myFileName;
var filename = $scope.filenameForVendor;
var formdata = new FormData();
formdata.append('File1', blob, filename);
$.ajax({
url: 'http://myvendorapi/ws/endpoint',
type: "POST",
data: formdata,
mimeType: "multipart/form-data",
processData: false,
contentType: false,
crossDomain: true,
success: function (result) {
console.log("Upload to Vendor complete!");
// rest of code here/including error close out
}
var bytes = atob(dataURL.split(',')[1])
var arr = new Uint8Array(bytes.length);
for (var i = 0; i < bytes.length; i++) {
arr[i] = bytes.charCodeAt(i);
}
send(new Blob([arr], { type: 'image/png' }));
Update:
I realized that contentType should be 'content-type'. When I did this, it creates an error of no boundary specified as I am trying multipart-form data (which I did all wrong). How can I pass formData to Node for uploading?
Update 2:
Per the advice offered, I tried using multer but am getting an ReferenceError: XMLHttpRequest is not defined.
Client side:
var fileTime = Date.now();
var myFileName = $scope.productCode + fileTime;
$scope.filenameForVendor = myFileName;
var filename = $scope.filenameForVendor;
var formdata = new FormData();
formdata.append('File1', blob, filename);
$http.post('/postVendor', formdata, { transformRequest: angular.identity, headers: { 'Content-Type': undefined } }).success(function (data) {
Server side:
app.post('/postVendor', function (req, res, next) {
var request = new XMLHttpRequest();
request.open("POST", "http://myvendorapi.net/ws/endpoint");
request.send(formData);
})
Why do you base64 encode the file?
You can upload raw file to your Node using FormData and you will not have to decode anything.
Front end
...
var request = new XMLHttpRequest();
request.open('POST', 'http://node.js/method');
request.send(formData); // vanilla
--- or ---
...
$http.post('http://node.js/method', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}); // angular
Back end
Just install request.
...
var request = require('request');
app.post('/method', function (req, res, next) {
// if you just want to push request you don't need to parse anything
req.pipe(request('http://vendor.net')).pipe(res);
}) // express
If I post a PDF to my vendors API, they return me a .png file as a blob (see update 2 as I am now unsure if they are returning blob data).
I would like to push this into Azure Blob Storage. Using my code listed below, it pushes something in, but the file is corrupted. Example: downloading the .png from Azure Blob Storage and trying to open it with Paint gives the following error:
This is not a valid bitmap file, or its format is not currently
supported.
I have verified that the image is sent to me correctly as the vendor is able to open the .png on their side. I am wondering if I need to convert this to base64 or save it to a local Web directory before uploading it to Azure Blob Storage.
Here is my Angular front end Controller that calls my Node/Express backend for uploading to Azure once it receives the returned "image":
$.ajax({
url: 'http://myvendorsapi.net/uploadPDF,
type: "POST",
data: formdata,
mimeType: "multipart/form-data",
processData: false,
contentType: false,
crossDomain: true,
success: function (result) {
var containerName = 'container1';
var filename = 'Texture_0.png';
var file = result;
$http.post('/postAdvanced', { containerName: containerName, filename: filename, file: file }).success(function (data) {
console.log("success!");
}, function (err) {
//console.log(err);
});
},
error: function (error) {
console.log("Something went wrong!");
}
})
}
Here is my Node/Express backend that uploads the blob to Azure Blob Storage. It gives no error, but the file can't be opened/gives the error stated above when opened in Paint:
app.post('/postAdvanced', function (req, res, next) {
var containerName = req.body.containerName;
var filename = req.body.filename;
var file = req.body.file;
blobSvc.createBlockBlobFromText(containerName, filename, file, function (error, result, response) {
if (!error) {
res.send(result);
}
else {
console.log(error);
}
});
})
Update 1: The answer provided here allows me to pass in the URL of the vendors API for some endpoints: Download file via Webservice and Push it to Azure Blob Storage via Node/Express
It works as it writes the file at the endpoint to a temp folder. In my current scenario, I upload a PDF file and it returns an image file that I need to upload to Azure Blob Storage. Is there a way to use the answer here, but adjust it for a file that I already have (since it is returned to me) versus file streaming from a URL?
Update 2: In console logging the returned "file", it looks like it may be data. I am not sure, it looks like this:
Is this actually data, and if so, how do I make this into a file for upload?
UPDATE 3:
Since it appears that jQuery AJAX can't manage binary returns. I am able to "open" the blob using XMLHTTPResponse as follows, but I can't seem to push this into Azure as it gives me the following error:
TypeError: must start with number, buffer, array or string
Here is my request. Note that the file opens properly:
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function (ev) {
var oData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", "http://myvendorsapi/Upload", true);
xhr.onload = function (oEvent) {
if (xhr.status == 200) {
var blob = new Blob([xhr.response], { type: "image/png" });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
console.log(blob);
var containerName = boxContainerName;
var filename = 'Texture_0.png';
$http.post('/postAdvanced', { containerName: containerName, filename: filename, file: blob }).success(function (data) {
//console.log(data);
console.log("success!");
}, function (err) {
//console.log(err);
});
} else {
oOutput.innerHTML = "Error " + xhr.status + " occurred when trying to upload your file.<br \/>";
}
};
xhr.send(oData);
ev.preventDefault();
}, false);
createBlockBlobFromText will work with either string or buffer. You might need a buffer to hold the binary content due to a known issue of jQuery.
For a workaround, there are several options:
Option 1: Reading binary filesusing jquery ajax
Option 2: Use native XMLHttpRequest
Option 3: Write frontend with Node as well and browserify it.
Your frontend code may look like:
var request = require('request');
request.post('http://myvendorsapi.net/uploadPDF', function (error, response, body) {
if (!error && response.statusCode == 200) {
var formData = {
containerName: 'container1',
filename: 'Texture_0.png',
file: body
};
request.post({ uri: '/postAdvanced', formData: formData }, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
} else {
console.log('Get snapshot failed!');
}
});
Then the backend code may look like:
app.post('/postAdvanced', function (req, res, next) {
var containerName = req.body.containerName;
var filename = req.body.filename;
var file = req.body.file;
if (!Buffer.isBuffer(file)) {
// Convert 'file' to a binary buffer
}
var options = { contentType: 'image/png' };
blobSvc.createBlockBlobFromText(containerName, filename, file, options, function (error, result, response) {
if (!error) {
res.send(result);
} else {
console.log(error);
}
});
})
Below I have the code to upload the image as binary in angular using FormData.
The server code will be the code to handle a regular file upload via a form.
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function (ev) {
var oData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", "http://vendorapi.net/Upload", true);
xhr.onload = function (oEvent) {
if (xhr.status == 200) {
var blob = new Blob([xhr.response], { type: "image/png" });
//var objectUrl = URL.createObjectURL(blob);
//window.open(objectUrl);
//console.log(blob);
var formData = new FormData()
formData.append('file', blob);
formData.append('containerName', boxContainerName);
formData.append('filename', 'Texture_0.png');
$http.post('/postAdvancedTest', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function (data) {
//console.log(data);
console.log("success!");
// Clear previous 3D render
$('#webGL-container').empty();
// Generated new 3D render
$scope.generate3D();
}, function (err) {
//console.log(err);
});
} else {
oOutput.innerHTML = "Error " + xhr.status + " occurred when trying to upload your file.<br \/>";
}
};
xhr.send(oData);
ev.preventDefault();
}, false);
I have solved the issue (thanks to Yang's input as well). I needed to base64 encode the data on the client side before passing it to node to decode to a file. I needed to use XMLHTTPRequest to get binary data properly, as jQuery AJAX appears to have an issue with returning (see here: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/).
Here is my front end:
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function (ev) {
var oData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", "http://vendorapi.net/Upload", true);
xhr.onload = function (oEvent) {
if (xhr.status == 200) {
var blob = new Blob([xhr.response], { type: "image/png" });
//var objectUrl = URL.createObjectURL(blob);
//window.open(objectUrl);
console.log(blob);
var blobToBase64 = function(blob, cb) {
var reader = new FileReader();
reader.onload = function() {
var dataUrl = reader.result;
var base64 = dataUrl.split(',')[1];
cb(base64);
};
reader.readAsDataURL(blob);
};
blobToBase64(blob, function(base64){ // encode
var update = {'blob': base64};
var containerName = boxContainerName;
var filename = 'Texture_0.png';
$http.post('/postAdvancedTest', { containerName: containerName, filename: filename, file: base64}).success(function (data) {
//console.log(data);
console.log("success!");
// Clear previous 3D render
$('#webGL-container').empty();
// Generated new 3D render
$scope.generate3D();
}, function (err) {
//console.log(err);
});
})
} else {
oOutput.innerHTML = "Error " + xhr.status + " occurred when trying to upload your file.<br \/>";
}
};
xhr.send(oData);
ev.preventDefault();
}, false);
Node Backend:
app.post('/postAdvancedTest', function (req, res) {
var containerName = req.body.containerName
var filename = req.body.filename;
var file = req.body.file;
var buf = new Buffer(file, 'base64'); // decode
var tmpBasePath = 'upload/'; //this folder is to save files download from vendor URL, and should be created in the root directory previously.
var tmpFolder = tmpBasePath + containerName + '/';
// Create unique temp directory to store files
mkdirp(tmpFolder, function (err) {
if (err) console.error(err)
else console.log('Directory Created')
});
// This is the location of download files, e.g. 'upload/Texture_0.png'
var tmpFileSavedLocation = tmpFolder + filename;
fs.writeFile(tmpFileSavedLocation, buf, function (err) {
if (err) {
console.log("err", err);
} else {
//return res.json({ 'status': 'success' });
blobSvc.createBlockBlobFromLocalFile(containerName, filename, tmpFileSavedLocation, function (error, result, response) {
if (!error) {
console.log("Uploaded" + result);
res.send(containerName);
}
else {
console.log(error);
}
});
}
})
})
I am unable to upload my images to AWS S3
{ [InvalidParameterType: Expected params.Body to be a string, Buffer,
Stream, Blob, or typed array object] message: 'Expected params.Body
to be a string, Buffer, Stream, Blob, or typed array object', code:
'InvalidParameterType',
Background
So this is what I am trying to do: first, I used Angular Image Cropper (http://andyshora.com/angular-image-cropper.html) to crop the image to a acceptable size for mobile. This gives a base64 URI.
Then, I used dataURItoBlob to convert the URI to blob, and attempt to upload to AWS S3.
The code looks like this:
Angular
$scope.dataURItoBlob= function(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
}
$scope.uploadPic = function() {
var base64data = document.getElementById('base64').value;
console.log("the data is: "+ base64data);
$scope.pic.Body = $scope.dataURItoBlob(base64data);
console.log("the blob is: "+ $scope.pic.Body);
$http({
method: 'POST',
url: '/api/upload/picture',
data: $scope.pic
}).success(function (data) {
//success code
});
};
Node (backend)
exports.uploadPicture = function (req, res) {
if (!req.body.hasOwnProperty('Key') || !req.body.hasOwnProperty('Body')) {
res.statusCode = 400;
return res.send('Error 400: Post syntax incorrect.');
} else {
var key = req.body.Key;
var body = req.body.Body;
AWS.config.loadFromPath('./config.json');
var s3 = new AWS.S3();
s3.createBucket({Bucket: 'bucket'}, function() {
var params = {Bucket: 'bucket', Key: key, Body: body};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err);
res.status(400).send('Bad Request.');
} else {
console.log("Successfully uploaded data to myBucket/myKey");
}
});
});
}
}
It fails because it is expecting a Blob but it is rejecting the Blob that I am sending in.. Please help!
Thanks!
what is inside your "var base64data"?
try this:
buf = new Buffer(req.body.imageBinary.replace(/^data:image\/\w+;base64,/, ""),'base64')
var data = {
Key: req.body.userId,
Body: buf,
ContentEncoding: 'base64',
ContentType: 'image/jpeg'
};
s3Bucket.putObject(data, function(err, data){
if (err) {
console.log(err);
console.log('Error uploading data: ', data);
} else {
console.log('succesfully uploaded the image!');
}
});
Hope that helps