2014-03-04 47 views
2

我想在Windows Azure上做一個網站,它允許用戶通過網頁提交一個文件與窗體,發送窗體與POST方法。我正在使用mac操作系統的最新版本,在mac book air 2013上。上傳,然後下載一個大文件,與Windows Azure,blob存儲和nodejs

服務器接收到此表單,將文件流式傳輸到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); 

這裏使用的引導和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> 
+0

嗨我在10月份有類似的問題,因此不得不使用標準上傳(首先寫入服務器)。但是現在Azure現在允許CORS,所以我正在嘗試生成一個SAS URL並直接上傳到Azure,而不需要多方或第三方上載。我讓你知道它是怎麼回事。 –

+0

嗨馬特,感謝您的評論。我正在嘗試CORS,以下是迄今爲止我已經結束的內容:http://stackoverflow.com/questions/22286856/windows-azure-set-blob-cors-properties-using-nodejs – user3380016

+0

看看我的回答[類似問題](http://stackoverflow.com/questions/6877376/any-way-to-set-access-control-allow-origin-for-a-windows-azure-blob/23192353#23192353) – Agni

回答

0

Microsoft長期以來一直在描述文件大小的兩個冪的單位,這可能會導致一些混淆。在Microsoft術語「54.33 MB」=(54.33 * 1024 * 1024)字節約爲57,000,000字節。因此,使用Microsoft工具查看文件,您所描述的行爲是「按設計」,但我明白它是否有點混亂。

這幾天,它可能更準確地說54。(MiB)約爲57 MB,但是當Microsoft使用MB = 1024 * 1024首次啓動時(1998年以前),這種Mebibyte術語根本就沒有。它只是你需要接受使用微軟系統的東西。