【问题标题】:Stream file to server from Cordova app从 Cordova 应用程序将文件流式传输到服务器
【发布时间】:2017-11-29 01:24:15
【问题描述】:

我有 cordova 应用程序,用户必须能够从手机中选择图像并将其上传到 AWS S3。我为此使用cordova-plugin-camera 和S3 SDK。我的代码可以正常工作(见下文),但需要将整个图像拉入内存中的 base64 编码字符串(每个Camera.DestinationType.DATA_URL),然后再拉入Buffer

我希望将其从手机的硬盘中流式传输,以缓解潜在的内存问题。 cordova-plugin-camera 网站甚至对此有警告:

/** * 警告:不推荐使用 DATA_URL! DATA_URL 目的地 * 类型非常占用内存,即使质量很低 环境。使用它 * 会导致内存不足错误和 应用程序崩溃。请改用 FILE_URI * 或 NATIVE_URI。 */

那么有没有办法使用FILE_URINATIVE_URI 或任何其他技术将照片直接从磁盘传输到S3?

这是我当前的代码:

doTheThing() {
    let options = {
        quality: 50,
        destinationType: Camera.DestinationType.DATA_URL,
        sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
        encodingType: Camera.EncodingType.JPG
    };

    navigator.camera.getPicture(imgData => {
       this.uploadToS3(imgData);
    }, options);


    uploadToS3(data) {
        let AWS = require('aws-sdk');

        AWS.config = new AWS.Config();
        AWS.config.accessKeyId = 'noway';
        AWS.config.secretAccessKey = 'jose';
        AWS.config.region = 'us-east-2';

        let s3 = new AWS.S3();
        let uploadParams = { Bucket: 'iamkule/f1/f2', Key: '', Body: new Buffer(data, 'base64') };
        uploadParams.Key = 'myfile.jpg';

        s3.upload(uploadParams, function (err, data) {
           if (data) {
              console.log('yay!');
           }
        });
    }
}

【问题讨论】:

标签: cordova amazon-s3 stream


【解决方案1】:

这应该可以帮助您入门。请原谅我的伪代码。随时根据需要对其进行编辑。

设备将图像保存到磁盘:

function takePicture(urlCallback){
    let options = {
        quality: 50,
        destinationType: Camera.DestinationType.FILE_URI,// <--
        sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
        encodingType: Camera.EncodingType.JPG
    };
    navigator.camera.getPicture(urlCallback, onFail, options);  
    function onFail(message) {
        alert('Failed because: ' + message);
    }
}

从磁盘获取图像作为 blob:

function getImageAsBlob(url, blobCallback) {
    var xhr = new XMLHttpRequest();
    xhr.open( "GET", url, true );
    xhr.responseType = "arraybuffer";
    xhr.onload = function( ev ) {
        // Obtain a blob: URL for the image data.
        var arrayBufferView = new Uint8Array( this.response );
        var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
        blobCallback(blob);
    };
    xhr.send();
}

将 blob 上传到 S3:

function uploadToS3(blob, callback) {
    let AWS = require('aws-sdk');
    AWS.config = new AWS.Config();
    AWS.config.accessKeyId = 'noway';
    AWS.config.secretAccessKey = 'jose';
    AWS.config.region = 'us-east-2';
    let s3 = new AWS.S3();
    let options = { Bucket: 'iamkule/f1/f2', Key: 'myfile.jpg', Body: blob };// <--
    s3.upload(options, callback);
}

把它们放在一起:

takePicture(function(url){
    getImageAsBlob(url, function(blob){
        uploadToS3(blob, function (err, data) {
            if (data) console.log('yay!');
        });
    });
});

S3 信息来自 here。照片拍摄信息来自here。 快乐编码!

【讨论】:

  • 感谢您的回答。我无法理解 getImageAsBlob() 函数中发生了什么。 url 参数应该是手机上图像文件的路径,但你没有用它做任何事情。相反,您正在从fiddle.jshell.cnet 下载图像?不知道我明白了。
  • 我已经修复了这个错误。代码没有经过端到端测试,但我在发布之前测试了我所能做的。该解决方案可能需要额外的更新,但应该可以帮助您入门。
  • 有趣,我不知道您可以使用 XMLHttpRequest 从文件系统中“获取”某些内容。虽然我很欣赏我的努力,但这并不能真正解决核心问题,因为它不会将文件从磁盘流式传输到 S3。您仍然将整个文件保存在内存中。不过,您确实消除了基本的 64 字节字符串,这很好。
  • 您必须设置权限才能访问设备的目录。我认为这是正确解决方案的原因是 S3 api 不提供支持自我管理分块或流实现的文件编写器。如果不重写 s3 sdk 代码并获得实现的所有权,您就会陷入整个文件处理的困境。该 blob 将至少比 base64 小 25%,并且不需要处理。如果在将二进制文件处理成 base64 之前加载两个二进制文件,base64 实现实际上可能比我提供的实现大 160% (2.6X)。
  • 这并没有提到这样一个事实,即如果您要在 s3 sdk 功能中实现任何节省,则很可能使用二进制来实现。您可以做的最好的事情是运行几次并分析每个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 2013-05-19
  • 2017-02-16
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
相关资源
最近更新 更多