【问题标题】:Upload HTML5 Canvas Converted to Image to Azure using Node/Express使用 Node/Express 将转换为图像的 HTML5 Canvas 上传到 Azure
【发布时间】:2015-12-12 07:16:39
【问题描述】:

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

 $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,如果我使用带有提交按钮的标准输入表单,我可以通过 Node 将图像上传到 Azure。这是用户通过文件输入和提交按钮手动上传的图像上传到 Azure Blob 存储的 Node/Express 代码,其中 /upload 在 HTML5 表单的表单操作上调用:

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 服务的工作示例,该 Web 服务上传通过 jQuery AJAX 转换为图像的 HTML5 画布)。本质上,由于我使用 Node/Express 来管理 Azure Blob 存储,因此我希望上传功能适用于我的 jQuery AJAX 示例。

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

AngularJS 前端控制器代码(绑定到名为“upload()”的 ng-click 按钮操作):

$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);
});
}

Node/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);
    }
});
});

当我点击“魔术按钮”将 Canvas 转换为图像(图像转换有效)并上传(上传无效)时,出现如下 Node 错误:

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

我还将“文件名”和“文件”记录到节点控制台并得到“未定义”。

客户端 我在浏览器的控制台中收到 500 内部服务器错误。但是,使用“网络”选项卡,我更深入地研究并看到“请求有效负载”的“文件”base64 编码和“文件名”是正确的。

我很大程度上怀疑我没有正确地将变量传递给 Node/Express,这就是导致 Azure 调用失败的原因。我还想知道由于通过输入表单上传图像是否适用于 Azure/Node,我是否应该以某种方式将转换后的 Canvas 作为 formdata 传递,但不确定如何实现/应该尝试它。

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

【问题讨论】:

    标签: node.js azure express


    【解决方案1】:

    我有一个测试项目来解决您的要求。并且有几个关键点我认为应该注意。

    Node/Express 后端部分:

    要在 Express 中获取 POST 数据,我们可以利用 bodyParser 中间件,它曾经是 Express 框架的内部部分。

    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;
    }
    

    取消注释部分直接通过base64字符串创建blob,注释部分先将图片保存为服务器上的文件,再通过文件创建blob。

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

    这是我的代码 sn-p:

    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();
    });
    

    棱角部分和你一样:

    $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);
            });
        }
    

    【讨论】:

    • 很好的解释加里,非常感谢代码示例。我会尽快测试它。两个快速的问题。为什么使用 router.post 和 app.post,使用 FromLocalFile 和 FromText 有区别吗?
    • 我相信既然我用的是Express 4.0,我不需要使用路由器:stackoverflow.com/questions/12695591/…
    • 想通了。切换到以下(不使用路由器),它现在正在工作。非常感谢@Gary Liu。 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false })); app.post('/postCanvas', function (req, res, next) {
    • 其实我提供了一个代码sn-p,它属于路由器的一部分,不能由单个文件运行。该架构显示在this article 中。对不起,我没有解释清楚。不管你还是想通了,恭喜。
    • 太棒了。这很有意义。欣赏后续和参考架构
    猜你喜欢
    • 2013-10-02
    • 2022-11-27
    • 2012-10-22
    • 2014-06-14
    • 2021-04-16
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    相关资源
    最近更新 更多