【问题标题】:Upload and then download a big file, with windows azure, blob storage and nodejs上传然后下载一个大文件,带有windows azure、blob storage和nodejs
【发布时间】:2014-07-16 10:08:13
【问题描述】:

我正在尝试在 windows azure 上做一个网站,它允许用户通过带有表单的网页提交文件,该表单使用 POST 方法发送表单。我在 mac book air 2013 上使用最新版本的 Mac OS。

服务器接收此表单,将文件流式传输到 blob,并将用户重定向到带有指向 blob 的链接(公开的)的新网页。这样,用户可以稍后获取他的文件。

我所做的似乎适用于小文件(图像约 35KB,dmg 文件约 950MB)。

但是当涉及到更大的文件(~20MB)时,服务器会注意到我在上传过程中出现错误(大约 1 分 20 秒或 2 分 40 秒后,不记得了)。客户端(谷歌浏览器)似乎没有意识到这一点,并继续上传文件。但是当它结束时,它会显示 503 错误。我尝试了 2 个大约 20MB 的 dmg 文件并得到了相同的结果(问题 1)。

然后使用 ~57MB dmg 文件(谷歌浏览器安装程序)和几个 ~700MB 文件(使用 ~30MB/s 上传互联网访问),服务器似乎没有任何问题,客户端也没有。上传过程直到结束,我得到了存储在 blob 存储中的文件的链接。但是当我下载它时,文件比预期的要大一点(57MB 文件多 4096 个字节,约 700MB 文件大约 40KB)。我尝试了几种类型的文件:能够重播视频已经足够了(尽管有一些奇怪的东西),但是当我尝试它时 dmg 无法安装(我猜是因为完整性检查做得很好)(问题 2 )

我想知道我的文件中添加了哪些数据。所以我创建了 2 个与我的 ~57MB dmg 文件大小相同的文件。第一个全是0字符,秒是0和1交替的。我上传下载的时候,没有原来的大小,但还是只有000000....或者010101010....不过,确实有更多的 0000... 和更多的 0101010.... 比原始版本(但只有 0 和 01)。

所以我转到 blob 存储管理器页面,发现每个文件的大小似乎都比我的计算机上的小(例如:54.33MB 而不是 ~57MB)。可能是因为不同的文件系统,...?

总结一下问题2:我上传了一个大文件,在网上看起来比我的笔记本要小,然后我下载下来,其实比原来的版本还大。很奇怪,不是吗?

有什么想法吗?感谢您的帮助!

这是我的 server.js 文件:

var http = require('http');
var url = require("url");
var express = require('express');
var querystring = require('querystring');
var fs = require('fs');
var path = require('path');
var azure = require('azure');
var multiparty = require('multiparty');
var tools = require('./tools.js');

var app = express();
app.use(express.logger("dev"));

var port = process.env.PORT || 1337;
var containerName = 'publicblobs';

app.use('/public', express.static('./public'));

/*
 * \brief Displays upload form
 */
app.get('(/|/upload/?)', function(req, res) {
    res.redirect('/public/upload.html');
});

/*
 * \brief Handles upload post request.
 */
app.post('/upload/request/?', function (req, res) {
    var blobService = azure.createBlobService();
    var form = new multiparty.Form();
    var currentFileName = 'undefinedCurrentFileName';

    blobService.createContainerIfNotExists(containerName
    , {publicAccessLevel : 'blob'}
    , function(error){
        if(!error){
            // Container exists and is public
        } else {
            res.render('log.ejs', {log: error.message});
        }
    });

    function gotPart(part) {
        if (part.filename) {
            console.log("New file received !");
            currentFileName = part.filename;
            var size = part.byteCount;
            console.log("file size : " + size);

            var onError = function(error) {
                if (error) {
                    console.log("blobService.createBlockBlobFromStream : on error");
                    res.render('log.ejs', {log: error.message});
                } else {
                    console.log("onError() : No error");
                }
            };
            blobService.createBlockBlobFromStream(containerName, currentFileName, part, size, onError);
        } else {
            console.log("New part received (not a file)");
            form.handlePart(part);
        }
    }
    form.on('part', gotPart);


    function reqEnd() {
        console.log("Upload completed!");
        res.redirect('/upload/complete/?'+
            // 'url='+req.get('host')+'/library/download/'+targetFileName+//'+req.get('host')+'
            '&fileName='+currentFileName+
            '&result=success');
    }
    req.on('end', reqEnd);

    function handleErrorCallback(error) { // inspired from http://stackoverflow.com/questions/18367824/how-to-cancel-http-upload-from-data-events
        var errorLog = "There was an error while receiving the request. The client may have put an end to the connection : " + error;
        console.log(errorLog);
    }

    req.on('error', handleErrorCallback);

    form.on('error', handleErrorCallback);

    form.parse(req);
});

/*
 * \brief Returns the file to the user.
 */
app.get('/library/download/:fileName', function(req, res) {
    fs.readFile('./public/uploaded/'+req.params.fileName, function(error,data){
        res.end(data);
    });
});

/*
 * \brief Inform the user about his uploaded file (and about error if need be)
 */
app.get('/upload/complete/?', function(req, res) {
    var params = querystring.parse(url.parse(req.url).query);
    res.setHeader('Content-Type', 'text/html');
    res.charset = 'utf8';
    if (params['result'] === 'success') {
        res.render('uploadComplete.ejs', {log: 'File '+params['fileName']+' uploaded to ', url: url.parse('http://'+process.env['AZURE_STORAGE_ACCOUNT']+'.blob.core.windows.net/'+containerName+'/'+params['fileName']).href});
    } else {
        res.render('uploadComplete.ejs', {log: 'An error occurred while uploading '+params['fileName']+' : '+params['log'], url: ''});
    }

});

/*
 * \brief Handles wrong addresses
 */
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');
    res.charset = 'utf8';
    console.log("Redirection due to the fact that the page has not been found.");
    res.redirect('/upload');
});

app.listen(port);

这是我使用 bootstrap 和 jquery 的表单:

<div class="container">

  <div class="starter-template">
    <form class="form-signin" role="form" action="/upload/request" method="post" enctype="multipart/form-data">
        <h2 class="form-signin-heading">Select a file to upload</h2>
        <label>
          <input type="file" name="filename2" id="filename2" class="form-control" required>
      </label>
      <button class="btn btn-lg btn-primary btn-block" type="submit">Upload</button>
    </form>
</div>

这是我的 web.config 文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <webSocket enabled="false" />
    <handlers>
      <add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
    </handlers>
    <rewrite>
      <rules>
        <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
          <match url="^server.js\/debug[\/]?" />
        </rule>
        <rule name="StaticContent">
          <action type="Rewrite" url="public{REQUEST_URI}"/>
        </rule>
        <rule name="DynamicContent">
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
          </conditions>
          <action type="Rewrite" url="server.js"/>
        </rule>
      </rules>
    </rewrite>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="1073741824"/>
      </requestFiltering>
    </security>
  </system.webServer>
  <system.web>
    <httpRuntime maxRequestLength="2097152"/>
  </system.web>
</configuration>

【问题讨论】:

  • 嘿,我在 10 月份遇到了类似的问题,因此只能使用标准上传(先写入服务器)。但是现在 Azure 现在允许 CORS,所以我尝试生成一个 SAS URL 并直接上传到 Azure,而不需要多方或第三方上传。我会告诉你进展如何。
  • 嗨,马特,感谢您的评论。我正在尝试使用 CORS,这就是我到目前为止所结束的内容:stackoverflow.com/questions/22286856/…
  • 看我对similar question的回复

标签: javascript node.js azure file-upload azure-blob-storage


【解决方案1】:

Microsoft 以二次幂为单位来描述文件大小的传统由来已久,这可能会引起一些混乱。在 Microsoft 术语中,“54.33 MB”= (54.33 * 1024 * 1024) 字节,大约为 57,000,000 字节。因此,使用 Microsoft 工具查看文件时,您所描述的行为是“设计使然”,尽管我理解它是否有点令人困惑。

这些天,可能更正确地说 54.33 Mebibytes (MiB) 大约是 57 MB,但是当 Microsoft 首次使用 MB = 1024 * 1024 时(1998 年之前),这根本不存在 Mebibyte 术语。它只是你需要接受使用微软系统的东西。

【讨论】:

    猜你喜欢
    • 2017-11-24
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 2020-12-23
    • 2014-01-23
    • 2021-07-02
    相关资源
    最近更新 更多