[英]Uploading a file in Azure File Storage using node.js
我們正在嘗試使用node.js服務創建Web服務以將文件上載到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 /'已超時。 這可能是由於腳本無法寫入響應,或者無法及時從異步調用返回而導致的。
更新:
我也試過下面的代碼。
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的參數流應該是一個對象”}
我是node.js的新手。 請幫我解決這個問題。
這里有幾個問題。 讓我們逐一介紹它們。
1.在Java客戶端中,您不能只將二進制數據轉儲到Azure移動服務連接中。
原因是Azure移動服務有兩個主體解析器,無論如何都能確保為您解析請求主體。 因此,雖然您可以通過指定不常見的內容類型來遍歷Express正文解析器,但您仍然會通過天真地假設它是UTF-8字符串來點擊Azure主體解析器,這會破壞您的數據流。
因此,唯一的選擇是通過指定無法處理的內容類型跳過Express解析器,然后通過使用Base64編碼對二進制數據進行編碼來與Azure解析器一起播放。
所以,在Java客戶端替換
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編碼器替換為您有權訪問的任何其他Base64編碼器。
2.您嘗試使用的createFileFromStream
Azure存儲api函數需要一個流。
同時,手動解析請求主體時可以獲得的最佳結果是字節數組。 不幸的是,Azure移動服務使用NodeJS版本0.8,這意味着沒有簡單的方法來構建來自字節數組的可讀流,並且您必須組裝適合Azure存儲API的自己的流。 一些膠帶和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。
請記住,因為您將數據作為Base64編碼傳輸,您必須考慮到這種開銷。 因此,要支持上傳大小為20Mb的文件,您必須將MS_MaxRequestBodySizeKB
設置為大約20 * 1024 * MS_MaxRequestBodySizeKB
= 27307。
當請求到達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 });
}
}
我發現最簡單的方法是使用pkgcloud來抽象雲提供商之間的差異,並提供一個干凈的界面來上傳和下載文件。 它使用流,因此實現也是內存效率。
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);
我們可以在SO上利用這個線程的答案如何通過HttpUrlConnection將圖像從Android客戶端發送到Node.js服務器? ,創建自定義中間件以將上傳文件內容放入緩沖區數組,然后我們可以使用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(可能是數據!)會產生損壞的圖像
2. createFileFromStream
或createWriteStreamToExistingFile
\\ createWriteStreamToNewFile
Azure存儲API可能對該功能有所幫助。
請注意,這些API是流的目標。 您需要將請求正文中的緩沖區/字符串轉換為流。 您可以參考如何將緩沖區包裝為stream2可讀流?
對於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
發生錯誤時,它也可能是網絡傳輸中的錯誤,您可能還希望返回錯誤代碼而不是statusCodes.OK
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.