Node.jsサービスを使用してAzureファイルストレージにファイルをアップロードするWebサービスを作成しようとしています。
以下は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 });
}
しかし、問題に直面している
{"エラー": "関数createFileFromStreamのパラメータストリームはオブジェクトである必要があります"}
Node.jsは初めてです。これを修正するのを手伝ってください。
ここにはいくつかの問題があります。それらを一つずつ見ていきましょう。
1。 Javaクライアントでは、バイナリデータをAzureモバイルサービス接続にダンプすることはできません。
これは、Azureモバイルサービスに2つのボディパーサーがあり、何があってもリクエストボディが解析されるようにするためです。そのため、一般的でないコンテンツタイプを指定することで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に適した独自のストリームをアセンブルする必要があります。一部のダクトテープと[email protected]は問題なく動作するはずです。
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でそれらを指定しても機能しない場合は、いつでもこれに移動して link に移動し、コンソールから手動でインストールできます。
cd site\wwwroot
npm install Azure-storage
npm install base64-js
npm install [email protected]
3。デフォルトのアップロード制限である1Mbを増やすには、サービスにMS_MaxRequestBodySizeKBを指定します。
ただし、Base64でエンコードされた状態でデータを転送するため、このオーバーヘッドを考慮する必要があることに注意してください。したがって、最大20Mbのサイズのファイルのアップロードをサポートするには、MS_MaxRequestBodySizeKB
を約20 * 1024 * 4/3 = 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 });
}
}
SO AndroidクライアントからHttpUrlConnection経由でNode.jsサーバーにイメージを送信する方法) でスレッドのこの回答を活用できます。 =、アップロードファイルのコンテンツをバッファー配列に取得するカスタムミドルウェアを作成し、createFileFromText()
を使用してファイルをAzureStorageに保存できます。
コードスニペットは次のとおりです。
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);
})
最も簡単な方法は 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);
いくつかのことがあります:
1。 createFileFromText
はプレーンテキストで機能します。ただし、UTF-8エンコーディングを使用しているため、これらのバイナリコンテンツでは失敗します。
次の場所でblobの同様の問題を参照することをお勧めします: AJAX Azure Blob Storageを呼び出すと破損したイメージが作成される によって返される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
の代わりにエラーコードを返すこともできます。