【发布时间】: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