使用node.js在Azure文件存储中上传文件

我们正在尝试创build一个web服务,使用node.js服务将file upload到Azure文件存储。

以下是node.js服务器代码。

exports.post = function(request, response){ var shareName = request.headers.sharename; var dirPath = request.headers.directorypath; var fileName = request.headers.filename; var body; var length; request.on("data", function(chunk){ body += chunk; console.log("Get data"); }); request.on("end", function(){ try{ console.log("end"); var data = body; length = data.length; console.log(body); // This giving the result as undefined console.log(length); fileService.createFileFromStream(shareName, dirPath, fileName, body, length, function(error, result, resp) { if (!error) { // file uploaded response.send(statusCodes.OK, "File Uploaded"); }else{ response.send(statusCodes.OK, "Error!"); } }); }catch (er) { response.statusCode = 400; return res.end('error: ' + er.message); } }); } 

以下是我们的客户端上传文件。

 private static void sendPOST() throws IOException { URL obj = new URL("https://crowdtest-fileservice.azure-mobile.net/api/files_stage/"); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("sharename", "newamactashare"); con.setRequestProperty("directorypath", "MaheshApp/TestLibrary/"); con.setRequestProperty("filename", "temp.txt"); Path path = Paths.get("C:/Users/uma.maheshwaran/Desktop/Temp.txt"); byte[] data = Files.readAllBytes(path); // For POST only - START con.setDoOutput(true); OutputStream os = con.getOutputStream(); os.write(data); os.flush(); os.close(); // For POST only - END int responseCode = con.getResponseCode(); System.out.println("POST Response Code :: " + responseCode); if (responseCode == HttpURLConnection.HTTP_OK) { // success BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); System.out.println(inputLine); } in.close(); // print result System.out.println(response.toString()); } else { BufferedReader br = new BufferedReader(new InputStreamReader(con.getErrorStream())); String line = ""; while ((line = br.readLine()) != null) { System.out.println(line); } System.out.println("POST request not worked"); } } 

这是显示错误

请求“POST / api / files_stage /”已超时。 这可能是由于脚本无法写入响应,或者无法及时从asynchronous调用返回。

更新:

我也尝试了下面的代码。

  var body = new Object(); body = request.body; var length = body.length; console.log(request.body); console.log(body); console.log(length); try { fileService.createFileFromStream(shareName, dirPath, fileName, body, length, function(error, result, resp) { if (!error) { // file uploaded response.send(statusCodes.OK, "File Uploaded"); }else{ response.send(statusCodes.OK, "Error!"); } }); } catch (ex) { response.send(500, { error: ex.message }); } 

但是面临这个问题

{“error”:“函数createFileFromStream的参数stream应该是一个对象”}

我是node.js的新手 请帮我解决这个问题。

       

网上收集的解决方案 "使用node.js在Azure文件存储中上传文件"

这里有几个问题。 让我们一个接一个地去看看。

1.在Java客户端中,您不能将二进制数据转储到Azure移动服务连接。

这样做的原因是Azure移动服务具有两个主体parsing器,可以确保无论如何都可以为您parsing请求主体。 因此,尽pipe您可以通过指定一个不常见的内容types来绕过Express bodyparsing器,但您仍然会击中Azure身体parsing器,这会通过天真地认为它是UTF-8string来混淆数据stream。

因此,唯一的select是通过指定它无法处理的内容types来跳过Expressparsing器,然后通过使用Base64编码对二进制数据进行编码来与Azureparsing器一起玩。

所以,在Java客户端replace

 Path path = Paths.get("C:/Users/uma.maheshwaran/Desktop/Temp.txt"); byte[] data = Files.readAllBytes(path); 

 con.setRequestProperty("content-type", "binary"); Path path = Paths.get("C:/Users/uma.maheshwaran/Desktop/Temp.txt"); byte[] data = Files.readAllBytes(path); data = Base64.getEncoder().encode(data); 

如果您不在Java 8上,请将java.util.Base64编码器replace为您有权访问的任何其他Base64编码器。

2.您尝试使用的createFileFromStream Azure存储API函数需要一个stream。

同时,手动parsing请求体时可以得到的最好的是一个字节数组。 不幸的是,Azure移动服务使用的是NodeJS 0.8版本,这意味着从字节数组中构造一个可读的stream并不容易,而且您必须组装适合Azure存储API的自己的stream。 一些胶带和stream@0.0.1应该没问题。

 var base64 = require('base64-js'), Stream = require('stream'), fileService = require('azure-storage') .createFileService('yourStorageAccount', 'yourStoragePassword'); exports.post = function (req, res) { var data = base64.toByteArray(req.body), buffer = new Buffer(data), stream = new Stream(); stream['_ended'] = false; stream['pause'] = function() { stream['_paused'] = true; }; stream['resume'] = function() { if(stream['_paused'] && !stream['_ended']) { stream.emit('data', buffer); stream['_ended'] = true; stream.emit('end'); } }; try { fileService.createFileFromStream(req.headers.sharename, req.headers.directorypath, req.headers.filename, stream, data.length, function (error, result, resp) { res.statusCode = error ? 500 : 200; res.end(); } ); } catch (e) { res.statusCode = 500; res.end(); } }; 

这些是你需要的这个样本的依赖关系。

 "dependencies": { "azure-storage": "^0.7.0", "base64-js": "^0.0.8", "stream": "0.0.1" } 

如果在您的服务的package.json中指定它们不起作用,您可以随时访问此链接并通过控制台手动安装它们。

 cd site\wwwroot npm install azure-storage npm install base64-js npm install stream@0.0.1 

3.要增加1Mb的默认上传限制,请为您的服务指定MS_MaxRequestBodySizeKB。

MS_MaxRequestBodySizeKB

不过请记住,因为您将数据以Base64编码方式传输,所以您必须考虑此开销。 因此,要支持上传大小为20Mb的文件,您必须将MS_MaxRequestBodySizeKB设置为大约20 * 1024 * MS_MaxRequestBodySizeKB = 27307。

我发现最简单的方法是使用pkgcloud ,它抽象出云提供者之间的差异,并提供一个干净的界面来上传和下载文件。 它使用stream,所以实现也是内存有效的。

 var pkgcloud = require('pkgcloud') var fs = require('fs') var client = pkgcloud.storage.createClient({ provider: 'azure', storageAccount: 'your-storage-account', storageAccessKey: 'your-access-key' }); var readStream = fs.createReadStream('a-file.txt'); var writeStream = client.upload({ container: 'your-storage-container', remote: 'remote-file-name.txt' }); writeStream.on('error', function (err) { // handle your error case }); writeStream.on('success', function (file) { // success, file will be a File model }); readStream.pipe(writeStream); 

当请求到达在exports.post定义的函数时,整个请求已经在那里,所以你不需要缓冲它。 你可以通过写下面的代码行来简化它。

 exports.post = function(request, response){ var shareName = request.headers.sharename; var dirPath = request.headers.directorypath; var fileName = request.headers.filename; var body = request.body; var length = body.length; console.log(length); try { fileService.createFileFromText(shareName, dirPath, fileName, body, function(error, result, resp) { if (!error) { // file uploaded response.send(statusCodes.OK, "File Uploaded"); } else { response.send(statusCodes.OK, "Error!"); } }); } catch (ex) { response.send(500, { error: ex.message }); } } 

我们可以利用这个线程的答案如何通过HttpUrlConnection发送Android客户端的图像到Node.js服务器? ,创build一个自定义的中间件来获取上传文件内容到缓冲区数组,然后我们可以使用createFileFromText()将文件存储在Azure存储中。

这里是代码片段:

 function rawBody(req, res, next) { var chunks = []; req.on('data', function (chunk) { chunks.push(chunk); }); req.on('end', function () { var buffer = Buffer.concat(chunks); req.bodyLength = buffer.length; req.rawBody = buffer; next(); }); req.on('error', function (err) { console.log(err); res.status(500); }); } router.post('/upload', rawBody,function (req, res){ fileService.createShareIfNotExists('taskshare', function (error, result, response) { if (!error) { // if result = true, share was created. // if result = false, share already existed. fileService.createDirectoryIfNotExists('taskshare', 'taskdirectory', function (error, result, response) { if (!error) { // if result = true, share was created. // if result = false, share already existed. try { fileService.createFileFromText('taskshare', 'taskdirectory', 'test.txt', req.rawBody, function (error, result, resp) { if (!error) { // file uploaded res.send(200, "File Uploaded"); } else { res.send(200, "Error!"); } }); } catch (ex) { res.send(500, { error: ex.message }); } } }); } }); }) router.get('/getfile', function (req, res){ fileService.createReadStream('taskshare', 'taskdirectory', 'test.txt').pipe(res); }) 

有几件事情:

1. createFileFromText可以使用纯文本。 但是对于那些二进制内容,它会失败,因为它使用UTF-8编码。

您可能想要引用类似的blob问题: 将AJAX调用返回的Azure Blob存储返回的Blob(可能是数据!)创build损坏的映像

2. createFileFromStreamcreateWriteStreamToExistingFile \ createWriteStreamToNewFile Azure存储API可能是可以帮助的function。

请注意,这些API是针对stream。 您需要将请求正文中的缓冲区/string转换为stream。 你可以参考如何将一个缓冲区打包为一个stream2可读stream?

对于createFileFromStream

 fileService.createFileFromStream(req.headers.sharename, req.headers.directorypath, req.headers.filename, requestStream, data.length, function (error, result, resp) { res.statusCode = error ? 500 : 200; res.end(); } ); 

对于createWriteStreamToNewFile

 var writeStream = fileService.createWriteStreamToNewFile(req.headers.sharename, req.headers.directorypath, req.headers.filename, data.length); requestStream.pipe(writeStream); 

3.你的代码有几个问题

 console.log(body); // This giving the result as undefined 

原因是你定义了var body ,它是undefined 。 代码body += chunk仍然会使body未定义。

 fileService.createFileFromStream(shareName, dirPath, fileName, body, length, function(error, result, resp) { if (!error) { // file uploaded response.send(statusCodes.OK, "File Uploaded"); }else{ response.send(statusCodes.OK, "Error!"); } }); 

createFileFromStream发生错误时,它也可能是networking传输中的错误,您可能还想返回错误代码而不是statusCodes.OK