使用Node / Express将HTML5 Canvas上传到Azure

正如标题所暗示的,这是一个有趣的用例。 我有一个HTML5canvas,我可以转换成图像。 我使用AngularJS作为前端,Node / Express作为我的站点的后端。 将HTML5 Canvas转换为图像可以按预期工作,并且可以使用jQuery AJAX(不使用Node / Express)将其上传到单独的Web Service,如下所示:

$scope.webService = function () { var send = function (blob) { var filename = 'Test.pdf'; var formdata = new FormData(); formdata.append('File1', blob, filename); $.ajax({ url: 'http://awebservice.net/endpoint', type: "POST", data: formdata, mimeType: "multipart/form-data", processData: false, contentType: false, crossDomain: true, success: function (result) { console.log("Upload complete!"); }, error: function (error) { console.log("Something went wrong!"); } }) } var canvasImage = document.getElementById("c"); if (!canvasImage.toBlob) { var dataURL = canvasImage.toDataURL(); 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' })); } else canvasImage.toBlob(send); } 

我在另一种情况下使用Node / Express,在这种情况下,如果我使用带有提交button的标准input表单,则可以通过节点将图像上载到Azure。 这里是上传到Azure Blob存储的Node / Express代码,用于通过用户通过文件input和提交button手动上传的图像,其中在HTML5表单的表单操作上调用/ upload:

 app.post('/upload4', function (req, res) { var form = new formidable.IncomingForm(); form.parse(req, function (err, fields, files) { var options = { contentType: files.myfile.type, metadata: { fileName: files.myfile.name } }; blobSvc.createBlockBlobFromLocalFile('blob5', files.myfile.name, files.myfile.path, options, function (error, result, response) { if (!error) { // file uploaded res.send('file uploaded!'); } }); }); console.log(req); }); 

但是,我需要通过转换后的HTML5 Canvas“幕后”,用户不必下载并通过Web表单重新上传HTML5 Canvas图像,而只需单击,即可转换Canvas并将图像上传到Azure(请参阅上面的第一个示例,其中使用不使用Node / Express的不同Web服务的工作示例,该服务通过jQuery AJAX将HTML5 Canvas上传到图像)。 从本质上讲,因为我使用Node / Express来pipe理Azure Blob存储,所以我想要在我的jQuery AJAX示例中使用上传function。

我设想我可以将图像数据/variables传递回Node / Express,如下所示:

AngularJS前端控制器代码(与名为“upload()”的ng-clickbutton绑定):

 $scope.upload = function () { var canvasImage = document.getElementById("c"); var img = canvasImage.toDataURL("image/png"); var filename = 'Texture_0.png'; $http.post('/upload', { filename: filename, file: img }).success(function (data) { console.log(data); }); } 

节点/ Express后端代码:

 app.post('/upload', function (req, res) { var filename = req.filename; var file = req.file; blobSvc.createBlockBlobFromLocalFile('mycontainer', filename, file, function (error, result, response) { if (!error) { console.log("Uploaded" + result); // file uploaded } else { console.log(error); } }); }); 

当我点击“魔法button”将canvas转换为图像(图像转换工作)和上传(上传不起作用),我得到一个节点错误,如下所示:

错误:未定义函数createBlockBlobFromFile所需的参数blob

我也logging了“文件名”和“文件”的节点控制台,并得到“未定义”。

客户端我在浏览器的控制台中收到500内部服务器错误。 然而,使用networking选项卡深入挖掘,看到“请求有效载荷”有“文件”base64编码和“文件名”是正确的。

我主要怀疑我没有正确地将variables传递给Node / Express,这就是Azure调用的绊脚石。 我也想知道,如果通过input窗体上传图像与Azure /节点,如果我应该以某种方式通过转换的canvas作为formdata,但不知道如何实现这个/应该尝试它。

我的问题是,如何传递正确的variables/数据,以便我的canvas可以从AngularJS前端上载到Azure Blob存储到Node / Express后端?

我有一个testing项目来制定你的要求。 而且我认为有几个关键点值得注意。

Node / Express后端部分:

为了在Express中获得POST数据,我们可以利用用作Express框架内部部分的bodyParser中间件。

 var bodyParser = require('body-parser'); var router = express.Router(); router.use(bodyParser.json()); router.use(bodyParser.urlencoded({ extended: false })); router.post('/postCanvas', function (req, res, next){ var filename = req.body.filename; var file = req.body.file; var base64Data; fileBuffer = decodeBase64Image(file); blobsrv.createBlockBlobFromText('container', filename, fileBuffer.data, {'contentType': fileBuffer.type}, function (error, result, response) { if (!error) { console.log("Uploaded" + result); } else { console.log(error); } }); /* fs.writeFileSync('upload/' + filename, fileBuffer.data); blobsrv.createBlockBlobFromLocalFile('container', filename, 'upload/' + filename, function (error, result, response) { if (!error) { console.log("Uploaded" + result); // file uploaded } else { console.log(error); } });*/ }) 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; } 

取消注释部分将直接通过base64string创build一个blob,注释部分将图像保存为服务器上的文件,然后通过文件创build一个blob。

如果您的服务器托pipe在Azure上,可能会遇到CROS问题。 所以我们需要在express.js框架中允许共享资源的共享。

这是我的代码片段:

 app.use(function (req, res, next) { res.setHeader("Access-Control-Allow-Origin", "http://localhost:8801"); res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); res.setHeader('Access-Control-Allow-Credentials', true); res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'); next(); }); 

angular部与你一样:

 $scope.upload = function () { var canvasImage = document.getElementById("myCanvas"); var img = canvasImage.toDataURL("image/jpeg"); var filename = 'Texture_0.jpg'; console.log(img); console.log(filename); $http.post('http://localhost:1337/postCanvas', { filename: filename, file: img }).success(function (data) { console.log(data); },function(err){ console.log(err); }); }