Added samples and Node.js version bundle scripts;
Added npm run genjs command for quick JavaScript SDK generating;
This commit is contained in:
Родитель
345e3d8475
Коммит
81b0dac3f5
|
@ -41,3 +41,6 @@ coverage
|
|||
# Tests artefacts
|
||||
fileservice_test_*
|
||||
blobservice_test.tmp
|
||||
|
||||
# Browserify bundle scripts
|
||||
browser/bundle
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
var AzureStorage = window.AzureStorage || {};
|
||||
|
||||
AzureStorage.generateDevelopmentStorageCredentials = function (proxyUri) {
|
||||
var devStore = 'UseDevelopmentStorage=true;';
|
||||
if(proxyUri){
|
||||
devStore += 'DevelopmentStorageProxyUri=' + proxyUri;
|
||||
}
|
||||
|
||||
return devStore;
|
||||
};
|
||||
|
||||
var BlobService = require('../lib/services/blob/blobservice');
|
||||
|
||||
AzureStorage.BlobService = BlobService;
|
||||
AzureStorage.BlobUtilities = require('../lib/services/blob/blobutilities');
|
||||
|
||||
AzureStorage.createBlobService = function (storageAccountOrConnectionString, storageAccessKey, host) {
|
||||
return new BlobService(storageAccountOrConnectionString, storageAccessKey, host, null);
|
||||
};
|
||||
|
||||
AzureStorage.createBlobServiceWithSas = function (host, sasToken) {
|
||||
return new BlobService(null, null, host, sasToken);
|
||||
};
|
||||
|
||||
AzureStorage.createBlobServiceAnonymous = function (host) {
|
||||
return new BlobService(null, null, host, null);
|
||||
};
|
||||
|
||||
var azureCommon = require('../lib/common/common');
|
||||
var StorageServiceClient = azureCommon.StorageServiceClient;
|
||||
var SharedKey = azureCommon.SharedKey;
|
||||
|
||||
AzureStorage.generateAccountSharedAccessSignature = function(storageAccountOrConnectionString, storageAccessKey, sharedAccessAccountPolicy)
|
||||
{
|
||||
var storageSettings = StorageServiceClient.getStorageSettings(storageAccountOrConnectionString, storageAccessKey);
|
||||
var sharedKey = new SharedKey(storageSettings._name, storageSettings._key);
|
||||
|
||||
return sharedKey.generateAccountSignedQueryString(sharedAccessAccountPolicy);
|
||||
};
|
||||
|
||||
AzureStorage.Constants = azureCommon.Constants;
|
||||
AzureStorage.StorageUtilities = azureCommon.StorageUtilities;
|
||||
AzureStorage.AccessCondition = azureCommon.AccessCondition;
|
||||
|
||||
AzureStorage.SR = azureCommon.SR;
|
||||
AzureStorage.StorageServiceClient = StorageServiceClient;
|
||||
AzureStorage.Logger = azureCommon.Logger;
|
||||
AzureStorage.WebResource = azureCommon.WebResource;
|
||||
AzureStorage.Validate = azureCommon.validate;
|
||||
AzureStorage.date = azureCommon.date;
|
||||
|
||||
// Other filters
|
||||
AzureStorage.LinearRetryPolicyFilter = azureCommon.LinearRetryPolicyFilter;
|
||||
AzureStorage.ExponentialRetryPolicyFilter = azureCommon.ExponentialRetryPolicyFilter;
|
||||
AzureStorage.RetryPolicyFilter = azureCommon.RetryPolicyFilter;
|
||||
|
||||
window.AzureStorage = AzureStorage;
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
var AzureStorage = window.AzureStorage || {};
|
||||
|
||||
AzureStorage.generateDevelopmentStorageCredentials = function (proxyUri) {
|
||||
var devStore = 'UseDevelopmentStorage=true;';
|
||||
if(proxyUri){
|
||||
devStore += 'DevelopmentStorageProxyUri=' + proxyUri;
|
||||
}
|
||||
|
||||
return devStore;
|
||||
};
|
||||
|
||||
var FileService = require('../lib/services/file/fileservice');
|
||||
|
||||
AzureStorage.FileService = FileService;
|
||||
AzureStorage.FileUtilities = require('../lib/services/file/fileutilities');
|
||||
|
||||
AzureStorage.createFileService = function (storageAccountOrConnectionString, storageAccessKey, host) {
|
||||
return new FileService(storageAccountOrConnectionString, storageAccessKey, host);
|
||||
};
|
||||
|
||||
AzureStorage.createFileServiceWithSas = function (hostUri, sasToken) {
|
||||
return new FileService(null, null, hostUri, sasToken);
|
||||
};
|
||||
|
||||
var azureCommon = require('../lib/common/common');
|
||||
var StorageServiceClient = azureCommon.StorageServiceClient;
|
||||
var SharedKey = azureCommon.SharedKey;
|
||||
|
||||
AzureStorage.generateAccountSharedAccessSignature = function(storageAccountOrConnectionString, storageAccessKey, sharedAccessAccountPolicy)
|
||||
{
|
||||
var storageSettings = StorageServiceClient.getStorageSettings(storageAccountOrConnectionString, storageAccessKey);
|
||||
var sharedKey = new SharedKey(storageSettings._name, storageSettings._key);
|
||||
|
||||
return sharedKey.generateAccountSignedQueryString(sharedAccessAccountPolicy);
|
||||
};
|
||||
|
||||
AzureStorage.Constants = azureCommon.Constants;
|
||||
AzureStorage.StorageUtilities = azureCommon.StorageUtilities;
|
||||
AzureStorage.AccessCondition = azureCommon.AccessCondition;
|
||||
|
||||
AzureStorage.SR = azureCommon.SR;
|
||||
AzureStorage.StorageServiceClient = StorageServiceClient;
|
||||
AzureStorage.Logger = azureCommon.Logger;
|
||||
AzureStorage.WebResource = azureCommon.WebResource;
|
||||
AzureStorage.Validate = azureCommon.validate;
|
||||
AzureStorage.date = azureCommon.date;
|
||||
|
||||
// Other filters
|
||||
AzureStorage.LinearRetryPolicyFilter = azureCommon.LinearRetryPolicyFilter;
|
||||
AzureStorage.ExponentialRetryPolicyFilter = azureCommon.ExponentialRetryPolicyFilter;
|
||||
AzureStorage.RetryPolicyFilter = azureCommon.RetryPolicyFilter;
|
||||
|
||||
window.AzureStorage = AzureStorage;
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
var AzureStorage = window.AzureStorage || {};
|
||||
|
||||
AzureStorage.generateDevelopmentStorageCredentials = function (proxyUri) {
|
||||
var devStore = 'UseDevelopmentStorage=true;';
|
||||
if(proxyUri){
|
||||
devStore += 'DevelopmentStorageProxyUri=' + proxyUri;
|
||||
}
|
||||
|
||||
return devStore;
|
||||
};
|
||||
|
||||
var QueueService = require('../lib/services/queue/queueservice');
|
||||
|
||||
AzureStorage.QueueService = QueueService;
|
||||
AzureStorage.QueueUtilities = require('../lib/services/queue/queueutilities');
|
||||
AzureStorage.QueueMessageEncoder = require('../lib/services/queue/queuemessageencoder');
|
||||
|
||||
AzureStorage.createQueueService = function (storageAccountOrConnectionString, storageAccessKey, host) {
|
||||
return new QueueService(storageAccountOrConnectionString, storageAccessKey, host);
|
||||
};
|
||||
|
||||
AzureStorage.createQueueServiceWithSas = function(hostUri, sasToken) {
|
||||
return new QueueService(null, null, hostUri, sasToken);
|
||||
};
|
||||
|
||||
var azureCommon = require('../lib/common/common');
|
||||
var StorageServiceClient = azureCommon.StorageServiceClient;
|
||||
var SharedKey = azureCommon.SharedKey;
|
||||
|
||||
AzureStorage.generateAccountSharedAccessSignature = function(storageAccountOrConnectionString, storageAccessKey, sharedAccessAccountPolicy)
|
||||
{
|
||||
var storageSettings = StorageServiceClient.getStorageSettings(storageAccountOrConnectionString, storageAccessKey);
|
||||
var sharedKey = new SharedKey(storageSettings._name, storageSettings._key);
|
||||
|
||||
return sharedKey.generateAccountSignedQueryString(sharedAccessAccountPolicy);
|
||||
};
|
||||
|
||||
AzureStorage.Constants = azureCommon.Constants;
|
||||
AzureStorage.StorageUtilities = azureCommon.StorageUtilities;
|
||||
AzureStorage.AccessCondition = azureCommon.AccessCondition;
|
||||
|
||||
AzureStorage.SR = azureCommon.SR;
|
||||
AzureStorage.StorageServiceClient = StorageServiceClient;
|
||||
AzureStorage.Logger = azureCommon.Logger;
|
||||
AzureStorage.WebResource = azureCommon.WebResource;
|
||||
AzureStorage.Validate = azureCommon.validate;
|
||||
AzureStorage.date = azureCommon.date;
|
||||
|
||||
// Other filters
|
||||
AzureStorage.LinearRetryPolicyFilter = azureCommon.LinearRetryPolicyFilter;
|
||||
AzureStorage.ExponentialRetryPolicyFilter = azureCommon.ExponentialRetryPolicyFilter;
|
||||
AzureStorage.RetryPolicyFilter = azureCommon.RetryPolicyFilter;
|
||||
|
||||
window.AzureStorage = AzureStorage;
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
var AzureStorage = window.AzureStorage || {};
|
||||
|
||||
AzureStorage.generateDevelopmentStorageCredentials = function (proxyUri) {
|
||||
var devStore = 'UseDevelopmentStorage=true;';
|
||||
if(proxyUri){
|
||||
devStore += 'DevelopmentStorageProxyUri=' + proxyUri;
|
||||
}
|
||||
|
||||
return devStore;
|
||||
};
|
||||
|
||||
var TableService = require('../lib/services/table/tableservice');
|
||||
AzureStorage.TableService = TableService;
|
||||
AzureStorage.TableQuery = require('../lib/services/table/tablequery');
|
||||
AzureStorage.TableBatch = require('../lib/services/table/tablebatch');
|
||||
AzureStorage.TableUtilities = require('../lib/services/table/tableutilities');
|
||||
|
||||
AzureStorage.createTableService = function (storageAccountOrConnectionString, storageAccessKey, host) {
|
||||
return new TableService(storageAccountOrConnectionString, storageAccessKey, host);
|
||||
};
|
||||
|
||||
AzureStorage.createTableServiceWithSas = function (hostUri, sasToken) {
|
||||
return new TableService(null, null, hostUri, sasToken);
|
||||
};
|
||||
|
||||
var azureCommon = require('../lib/common/common');
|
||||
var StorageServiceClient = azureCommon.StorageServiceClient;
|
||||
var SharedKey = azureCommon.SharedKey;
|
||||
|
||||
AzureStorage.generateAccountSharedAccessSignature = function(storageAccountOrConnectionString, storageAccessKey, sharedAccessAccountPolicy)
|
||||
{
|
||||
var storageSettings = StorageServiceClient.getStorageSettings(storageAccountOrConnectionString, storageAccessKey);
|
||||
var sharedKey = new SharedKey(storageSettings._name, storageSettings._key);
|
||||
|
||||
return sharedKey.generateAccountSignedQueryString(sharedAccessAccountPolicy);
|
||||
};
|
||||
|
||||
AzureStorage.Constants = azureCommon.Constants;
|
||||
AzureStorage.StorageUtilities = azureCommon.StorageUtilities;
|
||||
AzureStorage.AccessCondition = azureCommon.AccessCondition;
|
||||
|
||||
AzureStorage.SR = azureCommon.SR;
|
||||
AzureStorage.StorageServiceClient = StorageServiceClient;
|
||||
AzureStorage.Logger = azureCommon.Logger;
|
||||
AzureStorage.WebResource = azureCommon.WebResource;
|
||||
AzureStorage.Validate = azureCommon.validate;
|
||||
AzureStorage.date = azureCommon.date;
|
||||
|
||||
// Other filters
|
||||
AzureStorage.LinearRetryPolicyFilter = azureCommon.LinearRetryPolicyFilter;
|
||||
AzureStorage.ExponentialRetryPolicyFilter = azureCommon.ExponentialRetryPolicyFilter;
|
||||
AzureStorage.RetryPolicyFilter = azureCommon.RetryPolicyFilter;
|
||||
|
||||
window.AzureStorage = AzureStorage;
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
var browserify = require('browserify');
|
||||
var factor = require('factor-bundle');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var outputFolder = 'bundle';
|
||||
var outputFolderPath = path.resolve(__dirname, outputFolder);
|
||||
|
||||
console.log('Generating Azure Storage JavaScript Client Library to ' + outputFolderPath + ' ...\n');
|
||||
|
||||
if (!fs.existsSync(outputFolderPath)) {
|
||||
fs.mkdirSync(outputFolderPath);
|
||||
}
|
||||
|
||||
var b = browserify([
|
||||
path.resolve(__dirname, 'azure-storage.blob.export.js'),
|
||||
path.resolve(__dirname, 'azure-storage.file.export.js'),
|
||||
path.resolve(__dirname, 'azure-storage.queue.export.js'),
|
||||
path.resolve(__dirname, 'azure-storage.table.export.js')
|
||||
], {require: ['stream', 'util', 'buffer']});
|
||||
|
||||
b.plugin(factor, {
|
||||
outputs: [
|
||||
path.resolve(outputFolderPath, 'azure-storage.blob.js'),
|
||||
path.resolve(outputFolderPath, 'azure-storage.file.js'),
|
||||
path.resolve(outputFolderPath, 'azure-storage.queue.js'),
|
||||
path.resolve(outputFolderPath, 'azure-storage.table.js')
|
||||
]
|
||||
});
|
||||
|
||||
b.bundle().pipe(
|
||||
fs.createWriteStream(path.resolve(outputFolderPath, 'azure-storage.common.js'))
|
||||
);
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 13 KiB |
|
@ -0,0 +1,546 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Azure Storage JavaScript Client Library Sample for Blob Operations</title>
|
||||
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="mt-1">
|
||||
<h1>Azure Storage JavaScript Client Library Sample for Blob Operations</h1>
|
||||
</div>
|
||||
<p class="lead">In this sample, we will demonstrate common scenarios for Azure Blob Storage that includes creating, listing and deleting containers and blobs.</p>
|
||||
<hr/>
|
||||
<p>Azure Blob storage is a service for storing large amounts of unstructured object data, such as text or binary data, that can be accessed from anywhere in the world via HTTP or HTTPS. You can use Blob storage to expose data publicly to the world, or to store application data privately.</p>
|
||||
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Note</b>: You may need set up a HTTP server to host this sample for IE browser, because IndexedDB is only available on websites with http or https URL schemes in IE. Azure Storage JavaScript Client Library currently depends on IndexedDB.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Contents:</h2>
|
||||
<ul>
|
||||
<li><a href="#step1">Step 1: Preparing an Azure Storage account with CORS rules set</a></li>
|
||||
<li><a href="#step2">Step 2: Importing Azure Storage JavaScript Client Library</a></li>
|
||||
<li><a href="#step3">Step 3: Creating an Azure Storage BlobService Object</a></li>
|
||||
<li><a href="#step4">Step 4: Container Operations</a></li>
|
||||
<li><a href="#step5">Step 5: Blob Operations</a></li>
|
||||
<li><a href="#step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="step1">Step 1: Preparing an Azure Storage account with CORS rules set</h2>
|
||||
<p>Cross-origin resource sharing, or CORS, must be configured on the Azure Storage account to be accessed directly from JavaScript in the browser.
|
||||
You are able to set the CORS rules for specific Azure Storage account on the <a href="https://portal.azure.com">Azure Portal</a>.
|
||||
The "Allowed origins" could be set to "*" to allow all the origins in this sample.
|
||||
For more information about CORS, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services">Cross-Origin Resource Sharing (CORS)</a>.</p>
|
||||
<img src="cors.PNG"/>
|
||||
|
||||
<h2 id="step2">Step 2: Importing Azure Storage JavaScript Client Library</h2>
|
||||
<p>
|
||||
Importing <code>azure-storage.common.js</code> and <code>azure-storage.blob.js</code> in your HTML file for blob operations, and make sure <code>azure-storage.common.js</code> is in front of <code>azure-storage.blob.js</code>.
|
||||
<p>
|
||||
<pre>
|
||||
<script src="azure-storage.common.js"></script>
|
||||
<script src="azure-storage.blob.js"></script>
|
||||
</pre>
|
||||
|
||||
<h2 id="step3">Step 3: Creating an Azure Storage Blob Service Object</h2>
|
||||
<p>
|
||||
The <code>BlobService</code> object lets you work with containers and blobs.
|
||||
Following code creates a <code>BlobService</code> object with storage account and SAS Token.
|
||||
</p>
|
||||
<pre>
|
||||
var blobUri = 'https://' + 'STORAGE_ACCOUNT' + '.blob.core.windows.net';
|
||||
var blobService = AzureStorage.createBlobServiceWithSas(blobUri, 'SAS_TOKEN');
|
||||
</pre>
|
||||
<p>
|
||||
In Azure Storage JavaScript Client Library, a global variable <code>AzureStorage</code> is the start point where we can create service objects for blob/table/queue/file and access to the storage utilities.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>How to get full detailed API definitions? </b> Currently, the JavaScript Client Library shares the same API definitions with Node.js SDK.
|
||||
Please check API details on <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js API reference documents</a>. The JavaScript global variable <code>AzureStorage</code> is just like the object <code>require('azure-storage')</code> returns in Node.js.
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Warning</b>: Azure Storage JavaScript Client Library also supports creating <code>BlobService</code> based on Storage Account Key for authentication besides SAS Token.
|
||||
However, for security concerns, we recommend use of a limited time SAS Token, generated by a backend web server using a <a href="https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1">Stored Access Policy</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="step4">Step 4: Container Operations</h2>
|
||||
<p>
|
||||
A container provides a grouping of blobs. All blobs must be in a container. An account can contain an unlimited number of containers. A container can store an unlimited number of blobs. Note that the container name must be lowercase.
|
||||
<code>BlobService</code> object provides plenty of interfaces for container operations.
|
||||
</p>
|
||||
|
||||
<h3>List Containers</h3>
|
||||
<p><code>BlobService</code> provides <code>listContainersSegmented</code> and <code>listContainersSegmentedWithPrefix</code> for retrieving the containers list under a storage account.</p>
|
||||
<pre>
|
||||
blobService.listContainersSegmented(null, function (error, results) {
|
||||
if (error) {
|
||||
// List container error
|
||||
} else {
|
||||
for (var i = 0, container; container = results.entries[i]; i++) {
|
||||
// Deal with container object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Create Container</h3>
|
||||
<p><code>BlobService</code> provides <code>createContainer</code> and <code>createContainerIfNotExists</code> for creating a container under a storage account.</p>
|
||||
<pre>
|
||||
blobService.createContainerIfNotExists('mycontainer', function(error, result) {
|
||||
if (error) {
|
||||
// Create container error
|
||||
} else {
|
||||
// Create container successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Delete Container</h3>
|
||||
<p><code>BlobService</code> provides <code>deleteContainer</code> and <code>deleteContainerIfExists</code> for deleting a container under a storage account.</p>
|
||||
<pre>
|
||||
blobService.deleteContainerIfExists('mycontainer', function(error, result) {
|
||||
if (error) {
|
||||
// Delete container error
|
||||
} else {
|
||||
// Delete container successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Executable Example</h3>
|
||||
<p>
|
||||
The sample will try to create an Azure Storage blob service object based on SAS Token authorization.
|
||||
Enter your Azure Storage account name and SAS Token here, and executable examples in following steps dependent on the settings here.
|
||||
Make sure you have set the CORS rules for the Azure Storage blob service, and the SAS Token is in valid period.
|
||||
</p>
|
||||
<p>
|
||||
<label><b>Storage account:</b> </label> <input type="text" id="account"/>
|
||||
<label><b>SAS Token:</b> </label> <input type="text" id="sas"/>
|
||||
</p>
|
||||
<p>In the following executable example, you can try to list all the containers under your storage account settings, and try to create or delete one container from your account.</p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshContainer()">ListContainers</button> button to view the container list under your Azure Storage account</p></li>
|
||||
<li>
|
||||
<p> Click <button class="btn btn-xs btn-primary" onclick="createContainer()">CreateContainer</button> button to create a container under your Azure Storage account:</p>
|
||||
<p><label><b>New Container Name:</b> </label> <input type="text" value="mycontainer" id="newcontainer"/> </p>
|
||||
</li>
|
||||
<li><p> Click "<b>Delete</b>" button in the container list to delete the container under your Azure Storage account</p></li>
|
||||
<li><p> Click "<b>Select</b>" button to select and operate with the blobs in next step</p></li>
|
||||
</ul>
|
||||
<div id="containers"></div>
|
||||
|
||||
<h2 id="step5">Step 5: Blob Operations</h2>
|
||||
<p><b>Blob:</b> A file of any type and size. Azure Storage offers three types of blobs: block blobs, page blobs, and append blobs.</p>
|
||||
<p><b>Block blobs</b> are ideal for storing text or binary files, such as documents and media files. Append blobs are similar to block blobs in that they are made up of blocks, but they are optimized for append operations, so they are useful for logging scenarios. A single block blob can contain up to 50,000 blocks of up to 100 MB each, for a total size of slightly more than 4.75 TB (100 MB X 50,000). A single append blob can contain up to 50,000 blocks of up to 4 MB each, for a total size of slightly more than 195 GB (4 MB X 50,000).</p>
|
||||
<p><b>Page blobs</b> can be up to 1 TB in size, and are more efficient for frequent read/write operations. Azure Virtual Machines use page blobs as OS and data disks.</p>
|
||||
<p>For details about naming containers and blobs, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Naming-and-Referencing-Containers--Blobs--and-Metadata?redirectedfrom=MSDN">Naming and Referencing Containers, Blobs, and Metadata</a>.</p>
|
||||
|
||||
<h3>List Blobs</h3>
|
||||
<p><code>BlobService</code> provides <code>listBlobsSegmented</code> and <code>listBlobsSegmentedWithPrefix</code> for retrieving the blobs list under a container.</p>
|
||||
<pre>
|
||||
blobService.listBlobsSegmented('mycontainer', null, function (error, results) {
|
||||
if (error) {
|
||||
// List blobs error
|
||||
} else {
|
||||
for (var i = 0, blob; blob = results.entries[i]; i++) {
|
||||
// Deal with blob object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
<h3>Upload Blob</h3>
|
||||
<p><code>BlobService</code> provides <code>uploadBlobByStream</code> for uploading a blob from stream.
|
||||
However, currently <code>uploadBlobByStream</code> only accepts a Node.js <code>ReadableStream</code> type which pure JavaScript doesn't provide.
|
||||
</p>
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>Note</b>: After importing <code>azure-storage.common.js</code>, you could require 3 Node.js types: <code>stream</code>, <code>util</code> and <code>buffer</code>, then wrap a ReadableStream based on HTML5 <code>FileReader</code>.
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
// Provides a Stream for a file in webpage, inheriting from NodeJS Readable stream.
|
||||
var Buffer = require('buffer').Buffer;
|
||||
var Stream = require('stream');
|
||||
var util = require('util');
|
||||
|
||||
function FileStream(file, opt) {
|
||||
Stream.Readable.call(this, opt);
|
||||
|
||||
this.fileReader = new FileReader(file);
|
||||
this.file = file;
|
||||
this.size = file.size;
|
||||
this.chunkSize = 1024 * 1024 * 4; // 4MB
|
||||
this.offset = 0;
|
||||
var _me = this;
|
||||
|
||||
this.fileReader.onloadend = function loaded(event) {
|
||||
var data = event.target.result;
|
||||
var buf = Buffer.from(data);
|
||||
_me.push(buf);
|
||||
}
|
||||
}
|
||||
util.inherits(FileStream, Stream.Readable);
|
||||
FileStream.prototype._read = function() {
|
||||
if (this.offset > this.size) {
|
||||
this.push(null);
|
||||
} else {
|
||||
var end = this.offset + this.chunkSize;
|
||||
var slice = this.file.slice(this.offset, end);
|
||||
this.fileReader.readAsArrayBuffer(slice);
|
||||
this.offset = end;
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
<p>Uploading blob from stream. You can set up the blob name as well as the size of this uploading session. </p>
|
||||
<pre>
|
||||
// If one file has been selected in the HTML file input element
|
||||
var files = document.getElementById('fileinput').files;
|
||||
var file = files[0];
|
||||
var fileStream = new FileStream(file);
|
||||
|
||||
blobService.createBlockBlobFromStream('mycontainer', file.name, fileStream, file.size, {}, function(error, result, response) {
|
||||
if (error) {
|
||||
// Upload blob failed
|
||||
} else {
|
||||
// Upload successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Download Blob</h3>
|
||||
<p>
|
||||
<code>BlobService</code> provides interfaces for downloading a blob into browser memory.
|
||||
Because of browser's sandbox limitation, we cannot save the downloaded data trunks into disk until we get all the data trunks of a blob into browser memory.
|
||||
The browser's memory size is also limited especially for downloading huge blobs, so it's recommended to download a blob in browser with SAS Token authorized link directly.
|
||||
</p>
|
||||
<p>
|
||||
Shared access signatures (SAS) are a secure way to provide granular access to blobs and containers without providing your storage account name or keys. Shared access signatures are often used to provide limited access to your data, such as allowing a mobile app to access blobs.
|
||||
The following code example generates a new shared access policy that allows the shared access signatures holder to perform read operations on the myblob blob, and expires 100 minutes after the time it is created.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>Note: </b> You can choose to use the SAS Token in browser side, or generate a temporary SAS Token dynamically in your server side with Azure Storage C# or Node.js SDKs etc. according to your security requirements.
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
var downloadLink = blobService.getUrl('mycontainer', 'myblob', 'SAS_TOKEN');
|
||||
</pre>
|
||||
|
||||
<h3>Delete Blob</h3>
|
||||
<p><code>BlobService</code> provides <code>deleteContainer</code> and <code>deleteContainerIfExists</code> for deleting a blob under a storage account.</p>
|
||||
<pre>
|
||||
blobService.deleteBlobIfExists(container, blob, function(error, result) {
|
||||
if (error) {
|
||||
// Delete blob failed
|
||||
} else {
|
||||
// Delete blob successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
<h3>Executable Example</h3>
|
||||
<p>After clicked the "<b>Select</b>" button on the container list in last step, you are able to operate with the blobs under the selected container. </p><p><b><label>Selected container name: </label></b> <input type="text" id="container" disabled=true/></p>
|
||||
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshBlobList()">ListBlobs</button> button to view the blobs under your selected container</p></li>
|
||||
<li><p>
|
||||
Click <button id="upload-button" class="btn btn-xs btn-primary" onclick="uploadBlobByStream(false)">UploadBlob</button> button to upload a local file to current container after selecting a file:
|
||||
</p>
|
||||
<p> <input type="file" id="files" name="file" /> </p></li>
|
||||
<li><p> Click "<b>Delete</b>" button to delete the blob</p></li>
|
||||
<li><p> Click "<b>Download</b>" link to download a blob to local</p></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
<div> Uploaded Bytes: <font id="read"> </font> </div>
|
||||
<div class="progress">
|
||||
<div id="progress" class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
0%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="result"></div>
|
||||
|
||||
<h3 id="step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</h3>
|
||||
<ul>
|
||||
<li>1. Setting CORS rules for your selected Azure-Storage account blob service.</li>
|
||||
<li>2. Including "azure-storage.common.js" in the html file.</li>
|
||||
<li>3. Including functional file(s) needed, such as "azure-storage.blob.js" for blob operation.</li>
|
||||
<li>4. Using keyword "AzureStorage" to access to Azure storage JavaScript APIs.</li>
|
||||
<li>5. Referring to <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js SDK documents</a> for detailed API definitions which keep same with JavaScript APIs.</li>
|
||||
</ul>
|
||||
<p> You can view the source code of this sample for detailed reference. </p>
|
||||
</div>
|
||||
|
||||
<!-- azure-storage.common.js also exports Node.js module stream, util and buffer -->
|
||||
<script src="../bundle/azure-storage.common.js"></script>
|
||||
<script src="../bundle/azure-storage.blob.js"></script>
|
||||
|
||||
<script>
|
||||
// Provides a Stream for a file in webpage, inheriting from NodeJS Readable stream.
|
||||
var Stream = require('stream');
|
||||
var util = require('util');
|
||||
var Buffer = require('buffer').Buffer;
|
||||
|
||||
function FileStream(file, opt) {
|
||||
Stream.Readable.call(this, opt);
|
||||
|
||||
this.fileReader = new FileReader(file);
|
||||
this.file = file;
|
||||
this.size = file.size;
|
||||
this.chunkSize = 1024 * 1024 * 4; // 4MB
|
||||
this.offset = 0;
|
||||
var _me = this;
|
||||
|
||||
this.fileReader.onloadend = function loaded(event) {
|
||||
var data = event.target.result;
|
||||
var buf = Buffer.from(data);
|
||||
_me.push(buf);
|
||||
}
|
||||
}
|
||||
util.inherits(FileStream, Stream.Readable);
|
||||
FileStream.prototype._read = function() {
|
||||
if (this.offset > this.size) {
|
||||
this.push(null);
|
||||
} else {
|
||||
var end = this.offset + this.chunkSize;
|
||||
var slice = this.file.slice(this.offset, end);
|
||||
this.fileReader.readAsArrayBuffer(slice);
|
||||
this.offset = end;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var account = document.getElementById('account').value;
|
||||
var sas = document.getElementById('sas').value;
|
||||
var container = '';
|
||||
var blobUri = '';
|
||||
|
||||
function checkParameters() {
|
||||
account = document.getElementById('account').value;
|
||||
sas = document.getElementById('sas').value;
|
||||
|
||||
if (account == null || account.length < 1)
|
||||
{
|
||||
alert('Please enter a valid storage account name!');
|
||||
return false;
|
||||
}
|
||||
if (sas == null || sas.length < 1)
|
||||
{
|
||||
alert('Please enter a valid SAS Token!');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getBlobService() {
|
||||
if (!checkParameters())
|
||||
return null;
|
||||
|
||||
blobUri = 'https://' + account + '.blob.core.windows.net';
|
||||
var blobService = AzureStorage.createBlobServiceWithSas(blobUri, sas).withFilter(new AzureStorage.ExponentialRetryPolicyFilter());
|
||||
return blobService;
|
||||
}
|
||||
|
||||
function refreshContainer() {
|
||||
var blobService = getBlobService();
|
||||
if (!blobService)
|
||||
return;
|
||||
|
||||
document.getElementById('containers').innerHTML = 'Loading...';
|
||||
blobService.listContainersSegmented(null, function (error, results) {
|
||||
if (error) {
|
||||
alert('List container error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>ContainerName</th>',
|
||||
'<th>ContainerETag</th>',
|
||||
'<th>LastModified</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
if (results.entries.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, container; container = results.entries[i]; i++) {
|
||||
output.push('<tr>',
|
||||
'<td>', container.name, '</td>',
|
||||
'<td>', container.etag, '</td>',
|
||||
'<td>', container.lastModified, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteContainer(\'', container.name ,'\')">Delete</button> ',
|
||||
'<button class="btn btn-xs btn-success" onclick="viewContainer(\'', container.name ,'\')">Select</button>', '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('containers').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteContainer(name) {
|
||||
var blobService = getBlobService();
|
||||
if (!blobService)
|
||||
return;
|
||||
|
||||
blobService.deleteContainerIfExists(name, function(error, result) {
|
||||
if (error) {
|
||||
alert('Delete container failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete ' + name + ' successfully!');
|
||||
refreshContainer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createContainer() {
|
||||
var blobService = getBlobService();
|
||||
if (!blobService)
|
||||
return;
|
||||
|
||||
var container = document.getElementById('newcontainer').value;
|
||||
if (!AzureStorage.Validate.containerNameIsValid(container, function(err, res){})) {
|
||||
alert('Invalid container name!');
|
||||
return;
|
||||
}
|
||||
|
||||
blobService.createContainerIfNotExists(container, function(error, result){
|
||||
if (error) {
|
||||
alert('Create container failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Create ' + container + ' successfully!');
|
||||
refreshContainer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function viewContainer(selectedContainer) {
|
||||
container = selectedContainer;
|
||||
document.getElementById('container').value = container;
|
||||
alert('Selected ' + container + ' !');
|
||||
refreshBlobList();
|
||||
}
|
||||
|
||||
function refreshBlobList() {
|
||||
var blobService = getBlobService();
|
||||
if (!blobService)
|
||||
return;
|
||||
|
||||
document.getElementById('result').innerHTML = 'Loading...';
|
||||
blobService.createContainerIfNotExists(container, function(error, result) {
|
||||
if (error) {
|
||||
alert('createContainerIfNotExists error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
blobService.listBlobsSegmented(container, null, function (error, results) {
|
||||
if (error) {
|
||||
alert('List blob error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>BlobName</th>',
|
||||
'<th>ContentLength</th>',
|
||||
'<th>LastModified</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
if (results.entries.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, blob; blob = results.entries[i]; i++) {
|
||||
output.push('<tr>',
|
||||
'<td>', blob.name, '</td>',
|
||||
'<td>', blob.contentLength, '</td>',
|
||||
'<td>', blob.lastModified, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteBlob(\'', blob.name ,'\')">Delete</button> ',
|
||||
'<a class="btn btn-xs btn-success" href="', blobUri + '/' + container + '/' + blob.name + sas, '" download>Download</a>' , '</td>',
|
||||
'</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('result').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function deleteBlob(blob) {
|
||||
var blobService = getBlobService();
|
||||
if (!blobService)
|
||||
return;
|
||||
|
||||
blobService.deleteBlobIfExists(container, blob, function(error, result) {
|
||||
if (error) {
|
||||
alert('Delete blob failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete ' + blob + ' successfully!');
|
||||
refreshBlobList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function uploadBlobByStream(checkMD5) {
|
||||
var files = document.getElementById('files').files;
|
||||
if (!files.length) {
|
||||
alert('Please select a file!');
|
||||
return;
|
||||
}
|
||||
var file = files[0];
|
||||
|
||||
var blobService = getBlobService();
|
||||
if (!blobService)
|
||||
return;
|
||||
|
||||
var btn = document.getElementById("upload-button");
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = "Uploading";
|
||||
|
||||
var fileStream = new FileStream(file);
|
||||
|
||||
var options = {};
|
||||
options.storeBlobContentMD5 = checkMD5;
|
||||
var finishedOrError = false;
|
||||
var speedSummary = blobService.createBlockBlobFromStream(container, file.name, fileStream, file.size, options, function(error, result, response) {
|
||||
finishedOrError = true;
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = "UploadBlob";
|
||||
if (error) {
|
||||
alert('Upload filed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Upload successfully!');
|
||||
refreshBlobList();
|
||||
}
|
||||
});
|
||||
|
||||
function refreshProgress() {
|
||||
setTimeout(function() {
|
||||
if (!finishedOrError) {
|
||||
var process = speedSummary.getCompletePercent();
|
||||
document.getElementById("progress").style.width = process + '%';
|
||||
document.getElementById("progress").innerHTML = process + '%';
|
||||
refreshProgress();
|
||||
} else {
|
||||
document.getElementById("progress").style.width = '0%';
|
||||
document.getElementById("progress").innerHTML = '0%';
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
refreshProgress();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,646 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Azure Storage JavaScript Client Library Sample for File Operations</title>
|
||||
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="mt-1">
|
||||
<h1>Azure Storage JavaScript Client Library Sample for File Operations</h1>
|
||||
</div>
|
||||
<p class="lead">In this sample, we will demonstrate common scenarios for Azure File Storage that includes creating, listing and deleting file shares, directories and files.</p>
|
||||
<hr/>
|
||||
<p>Azure File storage is a service for storing large amounts of unstructured object data, such as text or binary data, that can be accessed from anywhere in the world via HTTP or HTTPS. You can use file storage to expose data publicly to the world, or to store application data privately.</p>
|
||||
<p>With Azure File storage, you can migrate legacy applications that rely on file shares to Azure quickly and without costly rewrites. Applications running in Azure virtual machines or cloud services or from on-premises clients can mount a file share in the cloud, just as a desktop application mounts a typical SMB share. Any number of application components can then mount and access the File storage share simultaneously. In this sample, you are able to create a file service with storage account and SAS Token. Based on the file service, you could create a file share, list files, upload files and delete files.</p>
|
||||
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Note</b>: You may need set up a HTTP server to host this sample for IE browser, because IndexedDB is only available on websites with http or https URL schemes in IE. Azure Storage JavaScript Client Library currently depends on IndexedDB.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Contents:</h2>
|
||||
<ul>
|
||||
<li><a href="#step1">Step 1: Preparing an Azure Storage account with CORS rules set</a></li>
|
||||
<li><a href="#step2">Step 2: Importing Azure Storage JavaScript Client Library</a></li>
|
||||
<li><a href="#step3">Step 3: Creating an Azure Storage File Service Object</a></li>
|
||||
<li><a href="#step4">Step 4: File Operations</a></li>
|
||||
<li><a href="#step5">Step 5: Directory and File Operations</a></li>
|
||||
<li><a href="#step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="step1">Step 1: Preparing an Azure Storage account with CORS rules set</h2>
|
||||
<p>Cross-origin resource sharing, or CORS, must be configured on the Azure Storage account to be accessed directly from JavaScript in the browser.
|
||||
You are able to set the CORS rules for specific Azure Storage account on the <a href="https://portal.azure.com">Azure Portal</a>.
|
||||
The "Allowed origins" could be set to "*" to allow all the origins in this sample.
|
||||
For more information about CORS, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services">Cross-Origin Resource Sharing (CORS)</a>.</p>
|
||||
<img src="cors.PNG"/>
|
||||
|
||||
<h2 id="step2">Step 2: Importing Azure Storage JavaScript Files</h2>
|
||||
<p>
|
||||
Importing <code>azure-storage.common.js</code> and <code>azure-storage.file.js</code> in your HTML file for file operations, and make sure <code>azure-storage.common.js</code> is in front of <code>azure-storage.file.js</code>.
|
||||
<p>
|
||||
<pre>
|
||||
<script src="azure-storage.common.js"></script>
|
||||
<script src="azure-storage.file.js"></script>
|
||||
</pre>
|
||||
|
||||
<h2 id="step3">Step 3: Creating an Azure Storage File Service Object</h2>
|
||||
<p>
|
||||
The <code>FileService</code> object lets you work with files and directories.
|
||||
Following code creates a <code>FileService</code> object with storage account and SAS Token.
|
||||
</p>
|
||||
<pre>
|
||||
var fileUri = 'https://' + 'STORAGE_ACCOUNT' + '.file.core.windows.net';
|
||||
var fileService = AzureStorage.createFileServiceWithSas(fileUri, 'SAS_TOKEN');
|
||||
</pre>
|
||||
<p>
|
||||
In Azure Storage JavaScript Client Library, a global variable <code>AzureStorage</code> is the start point where we can create service objects for blob/table/queue/file and access to the storage utilities.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>How to get full detailed API definitions? </b> Currently, the JavaScript Client Library shares the same API definitions with Node.js SDK.
|
||||
Please check API details on <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js API reference documents</a>. The JavaScript global variable <code>AzureStorage</code> is just like the object <code>require('azure-storage')</code> returns in Node.js.
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Warning</b>: Azure Storage JavaScript Client Library also supports creating <code>FileService</code> based on Storage Account Key for authentication besides SAS Token.
|
||||
However, for security concerns, we recommend use of a limited time SAS Token, generated by a backend web server using a <a href="https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1">Stored Access Policy</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="step4">Step 4: File Share Operations</h2>
|
||||
<p><b>Share</b>: A File storage share is an SMB file share in Azure. All directories and files must be created in a parent share. An account can contain an unlimited number of shares, and a share can store an unlimited number of files, up to the 5 TB total capacity of the file share.</p>
|
||||
|
||||
<h3>List File Shares</h3>
|
||||
<p><code>FileService</code> provides <code>listSharesSegmented</code> and <code>listSharesSegmentedWithPrefix</code> for listing file shares under a storage account.</p>
|
||||
<pre>
|
||||
fileService.listSharesSegmented(null, function(error, result) {
|
||||
if(error) {
|
||||
// List shares error
|
||||
} else {
|
||||
for (var i = 0, share; share = results.entries[i]; i++) {
|
||||
// Deal with share object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Create File Share</h3>
|
||||
<p><code>FileService</code> provides <code>createShare</code> and <code>createShareIfNotExists</code> for creating a file share under a storage account.</p>
|
||||
<pre>
|
||||
fileService.createShareIfNotExists('myshare', function(error, result) {
|
||||
if(error) {
|
||||
// Create share error
|
||||
} else {
|
||||
// Create share successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Delete File Share</h3>
|
||||
<p><code>FileService</code> provides <code>deleteShare</code> and <code>deleteShareIfExists</code> for deleting a file share under a storage account.</p>
|
||||
<pre>
|
||||
fileService.deleteShareIfExists('myshare', function(error, result) {
|
||||
if(error) {
|
||||
// Delete share error
|
||||
} else {
|
||||
// Delete share successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Executable Example</h3>
|
||||
<p>The sample will try to create an Azure Storage file service object based on SAS Token authorization. Enter your Azure Storage account name and SAS Token here. Make sure you have set the CORS rules for the Azure Storage file service, and the SAS Token is in valid period.</p>
|
||||
<label><b>Storage account:</b> </label> <input type="text" id="account"/>
|
||||
<label><b>SAS Token:</b> </label> <input type="text" id="sas"/>
|
||||
<p> Azure Storage file service provides plenty of interfaces for file operations. In following example, you can try to list all the file shares under your storage account, and try to create or delete one file share from your account.</p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshFileShareList()">ListFileShares</button> button to view the file share list under your Azure Storage account</p></li>
|
||||
<li>
|
||||
<p> Click <button class="btn btn-xs btn-primary" onclick="createFileShare()">CreateFileShare</button> button to create a file share under your Azure Storage account</p>
|
||||
<p><label><b>New File Share Name:</b> </label> <input type="text" value="myfileshare" id="newfileshare"/> </p>
|
||||
</li>
|
||||
<li><p> Click "<b>Delete</b>" button to delete the file share under your Azure Storage account</p></li>
|
||||
<li><p> Click "<b>Select</b>" button to operate with the directories and files in next step</p></li>
|
||||
</ul>
|
||||
<div id="result"></div>
|
||||
|
||||
<h2 id="step5">Step 5: Directory and File Operations</h2>
|
||||
<p><b>Directory</b> in storage is an optional hierarchy of directories.</p>
|
||||
<p><b>File</b>: A file in the share. A file may be up to 1 TB in size.</p>
|
||||
|
||||
<h3>List Files and Directories</h3>
|
||||
<p><code>FileService</code> provides <code>listFilesAndDirectoriesSegmented</code> for listing directories and files under a file share.</p>
|
||||
<pre>
|
||||
fileService.listFilesAndDirectoriesSegmented('myfileshare', '', null, function(error, result, response) {
|
||||
if(error) {
|
||||
// List table entity error
|
||||
} else {
|
||||
for (var i = 0, dir; dir = results.entries.directories[i]; i++) {
|
||||
// Deal with directory object
|
||||
}
|
||||
for (var i = 0, file; file = results.entries.files[i]; i++) {
|
||||
// Deal with file object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Create Directory</h3>
|
||||
<p><code>FileService</code> provides <code>createDirectory</code> and <code>createDirectoryIfNotExists</code> for creating directories under a file share.</p>
|
||||
<pre>
|
||||
fileService.createDirectoryIfNotExists('myfileshare', 'mydirectory', function(error, result, response) {
|
||||
if(error) {
|
||||
// Create directory error
|
||||
} else {
|
||||
// Create directory successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Delete Directory</h3>
|
||||
<p><code>FileService</code> provides <code>deleteDirectory</code> and <code>deleteDirectoryIfExists</code> for deleting directories under a file share.</p>
|
||||
<pre>
|
||||
fileService.deleteDirectoryIfExists('myfileshare', 'mydirectory', function(error, result, response) {
|
||||
if(error) {
|
||||
// Delete directory error
|
||||
} else {
|
||||
// Delete directory successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Upload File</h3>
|
||||
<p><code>FileService</code> provides <code>createFileFromStream</code> for uploading a file from stream.
|
||||
However, currently <code>createFileFromStream</code> only accepts a Node.js <code>ReadableStream</code> type which pure JavaScript doesn't provide.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>Note</b>: After importing <code>azure-storage.common.js</code>, you could require 3 Node.js types: <code>stream</code>, <code>util</code> and <code>buffer</code>, then wrap a ReadableStream based on HTML5 <code>FileReader</code>.
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
// Provides a Stream for a file in webpage, inheriting from NodeJS Readable stream.
|
||||
var Stream = require('stream');
|
||||
var util = require('util');
|
||||
var Buffer = require('buffer').Buffer;
|
||||
|
||||
function FileStream(file, opt) {
|
||||
Stream.Readable.call(this, opt);
|
||||
|
||||
this.fileReader = new FileReader(file);
|
||||
this.file = file;
|
||||
this.size = file.size;
|
||||
this.chunkSize = 1024 * 1024 * 4; // 4MB
|
||||
this.offset = 0;
|
||||
var _me = this;
|
||||
|
||||
this.fileReader.onloadend = function loaded(event) {
|
||||
var data = event.target.result;
|
||||
var buf = Buffer.from(data);
|
||||
_me.push(buf);
|
||||
}
|
||||
}
|
||||
util.inherits(FileStream, Stream.Readable);
|
||||
FileStream.prototype._read = function() {
|
||||
if (this.offset > this.size) {
|
||||
this.push(null);
|
||||
} else {
|
||||
var end = this.offset + this.chunkSize;
|
||||
var slice = this.file.slice(this.offset, end);
|
||||
this.fileReader.readAsArrayBuffer(slice);
|
||||
this.offset = end;
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
<p>Uploading file from stream. You can set up the file name as well as the size of this uploading session. </p>
|
||||
<pre>
|
||||
// If one file has been selected in the HTML file input element
|
||||
var files = document.getElementById('fileinput').files;
|
||||
var file = files[0];
|
||||
var fileStream = new FileStream(file);
|
||||
|
||||
fileService.createFileFromStream('myfileshare', 'mydirectory', file.name, fileStream, file.size, {}, function(error, result, response) {
|
||||
if (error) {
|
||||
// Upload file failed
|
||||
} else {
|
||||
// Upload successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Download File</h3>
|
||||
<p>
|
||||
<code>FileService</code> provides interfaces for downloading a file into browser memory directly.
|
||||
Because of browser's sandbox limitation, we cannot save the downloaded data trunks into disk until we get all the data trunks of a file into browser memory.
|
||||
The browser's memory size is also limited especially for downloading huge files, so it's recommended to download a file in browser with SAS Token authorized link directly.
|
||||
</p>
|
||||
<p>
|
||||
Shared access signatures (SAS) are a secure way to provide granular access to files and directories without providing your storage account name or keys. Shared access signatures are often used to provide limited access to your data, such as allowing a mobile app to access files.
|
||||
The following code example generates a new shared access policy that allows the shared access signatures holder to perform read operations on the myfile file, and expires 100 minutes after the time it is created.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>Note: </b> You can choose to use the SAS Token in browser side, or generate a temporary SAS Token dynamically in your server side with Azure Storage C# or Node.js SDKs etc. according to your security requirements.
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
var downloadLink = fileService.getUrl('myshare', 'mydirectory', 'myfile', 'SAS_TOKEN');
|
||||
</pre>
|
||||
|
||||
<h3>Delete File</h3>
|
||||
<p><code>FileService</code> provides <code>deleteFile</code> and <code>deleteFileIfExists</code> for deleting files under a file share.</p>
|
||||
<pre>
|
||||
fileService.deleteFileIfExists('myfileshare', 'mydirectory', 'myfile', function(error, result, response) {
|
||||
if(error) {
|
||||
// Delete file error
|
||||
} else {
|
||||
// Delete file successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Executable Example</h3>
|
||||
<p>After clicked the "<b>Select</b>" button on the file share list, you are able to operate with the directories and files under the selected file share.<p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshDirectoryFileList()">ListFilesAndDirectories</button> button to view the directories and files under your selected file share</p></li>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="createDirectory()">CreateDirectory</button> button to create a directory share under your current directory</p>
|
||||
<p><label><b>New Directory Name:</b> </label> <input type="text" value="mydirectory" id="newdirectory"/> </p>
|
||||
</li>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="backDirectory()">GoToUpperDirectory</button> button to return to upper level directory</p></li>
|
||||
<li><p> Click <button id="upload-button" class="btn btn-xs btn-primary" onclick="createFileFromStream(false)">Upload</button> button to upload a local file to current directory</p>
|
||||
<p><input type="file" id="files" name="file" /></p></li>
|
||||
<li><p> Click "<b>Delete</b>" button to delete the directory or file</p></li>
|
||||
<li><p> Click "<b>Download</b>" link to download a file to local</p></li>
|
||||
</ul>
|
||||
|
||||
<b>Current Path:<a id="path"></a></b>
|
||||
<div> Uploaded Bytes: <font id="read"> </font> </div>
|
||||
<div class="progress">
|
||||
<div id="progress" class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
0%
|
||||
</div>
|
||||
</div>
|
||||
<div id="directoryFiles"></div>
|
||||
|
||||
<h3 id="step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</h3>
|
||||
<ul>
|
||||
<li>1. Setting CORS rules for your selected Azure-Storage account file service.</li>
|
||||
<li>2. Including "azure-storage.common.js" in the html file.</li>
|
||||
<li>3. Including functional file(s) needed, such as "azure-storage.file.js" for file operation.</li>
|
||||
<li>4. Using keyword "AzureStorage" to access to Azure storage JavaScript APIs.</li>
|
||||
<li>5. Referring to <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js SDK documents</a> for detailed API definitions which keep same with JavaScript APIs.</li>
|
||||
</ul>
|
||||
<p> You can view the source code of this sample for detailed reference. </p>
|
||||
</div>
|
||||
|
||||
<script src="../bundle/azure-storage.common.js"></script>
|
||||
<script src="../bundle/azure-storage.file.js"></script>
|
||||
|
||||
<script>
|
||||
// Provides a Stream for a file in webpage, inheriting from NodeJS Readable stream.
|
||||
var Stream = require('stream');
|
||||
var util = require('util');
|
||||
var Buffer = require('buffer').Buffer;
|
||||
|
||||
function FileStream(file, opt) {
|
||||
Stream.Readable.call(this, opt);
|
||||
|
||||
this.fileReader = new FileReader(file);
|
||||
this.file = file;
|
||||
this.size = file.size;
|
||||
this.chunkSize = 1024 * 1024 * 4; // 4MB
|
||||
this.offset = 0;
|
||||
var _me = this;
|
||||
|
||||
this.fileReader.onloadend = function loaded(event) {
|
||||
var data = event.target.result;
|
||||
var buf = Buffer.from(data);
|
||||
_me.push(buf);
|
||||
}
|
||||
}
|
||||
util.inherits(FileStream, Stream.Readable);
|
||||
FileStream.prototype._read = function() {
|
||||
if (this.offset > this.size) {
|
||||
console.log('FileStream reaches file end');
|
||||
this.push(null);
|
||||
} else {
|
||||
var end = this.offset + this.chunkSize;
|
||||
var slice = this.file.slice(this.offset, end);
|
||||
this.fileReader.readAsArrayBuffer(slice);
|
||||
this.offset = end;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var account = document.getElementById('account').value;
|
||||
var sas = document.getElementById('sas').value;
|
||||
var fileShare = '';
|
||||
var currentPath = '';
|
||||
var fileUri = '';
|
||||
var currentPath = [];
|
||||
|
||||
function checkParameters() {
|
||||
account = document.getElementById('account').value;
|
||||
sas = document.getElementById('sas').value;
|
||||
|
||||
if (account == null || account.length < 1)
|
||||
{
|
||||
alert('Please enter a valid storage account name!');
|
||||
return false;
|
||||
}
|
||||
if (sas == null || sas.length < 1)
|
||||
{
|
||||
alert('Please enter a valid SAS Token!');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getFileService() {
|
||||
if (!checkParameters())
|
||||
return null;
|
||||
|
||||
fileUri = 'https://' + account + '.file.core.windows.net';
|
||||
var fileService = AzureStorage.createFileServiceWithSas(fileUri, sas).withFilter(new AzureStorage.ExponentialRetryPolicyFilter());
|
||||
return fileService;
|
||||
}
|
||||
|
||||
function refreshFileShareList()
|
||||
{
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
document.getElementById('result').innerHTML = 'Loading...';
|
||||
fileService.listSharesSegmented(null, function (error, results) {
|
||||
if (error) {
|
||||
alert('List file share error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>ShareName</th>',
|
||||
'<th>ShareETag</th>',
|
||||
'<th>ShareQuota</th>',
|
||||
'<th>LastModified</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
if (results.entries.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, share; share = results.entries[i]; i++) {
|
||||
output.push('<tr>',
|
||||
'<td>', share.name, '</td>',
|
||||
'<td>', share.etag, '</td>',
|
||||
'<td>', share.quota, '</td>',
|
||||
'<td>', share.lastModified, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteFileShare(\'', share.name ,'\')">Delete</button> ',
|
||||
'<button class="btn btn-xs btn-success" onclick="viewFileShare(\'', share.name ,'\')">Select</button>', '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('result').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteFileShare(name) {
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
fileService.deleteShareIfExists(name, function(error, result){
|
||||
if (error) {
|
||||
alert('Delete file share failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete ' + name + ' successfully!');
|
||||
refreshFileShareList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFileShare() {
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
var share = document.getElementById('newfileshare').value;
|
||||
if (!AzureStorage.Validate.shareNameIsValid(share, function(err, res){})) {
|
||||
alert('Invalid share name!');
|
||||
return;
|
||||
}
|
||||
|
||||
fileService.createShareIfNotExists(share, function(error, result){
|
||||
if (error) {
|
||||
alert('Create file share failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Create ' + share + ' successfully!');
|
||||
refreshFileShareList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function viewFileShare(selectedFileShare) {
|
||||
fileShare = selectedFileShare;
|
||||
alert('Selected ' + fileShare + ' !');
|
||||
currentPath = [];
|
||||
refreshDirectoryFileList();
|
||||
}
|
||||
|
||||
function backDirectory() {
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
if (fileShare.length < 1) {
|
||||
alert('Please select one file share!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPath.length > 0)
|
||||
currentPath.pop();
|
||||
|
||||
refreshDirectoryFileList();
|
||||
}
|
||||
|
||||
function refreshDirectoryFileList(directory)
|
||||
{
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
if (fileShare.length < 1) {
|
||||
alert('Please select one file share!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof directory === 'undefined')
|
||||
var directory = '';
|
||||
if (directory.length > 0)
|
||||
currentPath.push(directory);
|
||||
directory = currentPath.join('\\\\');
|
||||
|
||||
document.getElementById('directoryFiles').innerHTML = 'Loading...';
|
||||
fileService.listFilesAndDirectoriesSegmented(fileShare, directory, null, function (error, results) {
|
||||
if (error) {
|
||||
alert('List directories and files error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
document.getElementById('path').innerHTML = directory;
|
||||
|
||||
var outputDirectory = [];
|
||||
outputDirectory.push('<tr>',
|
||||
'<th>Type</th>',
|
||||
'<th>Name</th>',
|
||||
'<th>ContentLength</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
if (results.entries.directories.length < 1 && results.entries.files.length < 1) {
|
||||
outputDirectory.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, dir; dir = results.entries.directories[i]; i++) {
|
||||
outputDirectory.push('<tr>',
|
||||
'<td>', 'DIR', '</td>',
|
||||
'<td>', dir.name, '</td>',
|
||||
'<td>', dir.contentLength, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteDirectory(\'', dir.name ,'\')">Delete</button> ',
|
||||
'<button class="btn btn-xs btn-success" onclick="refreshDirectoryFileList(\'', dir.name ,'\')">View</button>', '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
|
||||
var outputFiles = [];
|
||||
var currentDir = currentPath.join('\\');
|
||||
if (currentPath.length > 0)
|
||||
currentDir += '/';
|
||||
|
||||
for (var i = 0, file; file = results.entries.files[i]; i++) {
|
||||
outputFiles.push('<tr>',
|
||||
'<td>', 'FILE', '</td>',
|
||||
'<td>', file.name, '</td>',
|
||||
'<td>', file.contentLength, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteFile(\'', file.name ,'\')">Delete</button> ',
|
||||
'<a class="btn btn-xs btn-success" href="', fileUri + '/' + fileShare + '/' + currentDir + file.name + sas, '" download>Download</a>' , '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('directoryFiles').innerHTML = '<table class="table table-condensed table-bordered">' + outputDirectory.join('') + outputFiles.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteDirectory(name) {
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
if (fileShare.length < 1) {
|
||||
alert("Please select a file share!");
|
||||
return;
|
||||
}
|
||||
|
||||
fileService.deleteDirectoryIfExists(fileShare, currentPath.join('\\\\') + '\\' + name, function(error, results) {
|
||||
if (error) {
|
||||
alert("Delete directory failed, open brower console for more detailed info.");
|
||||
console.log(error);
|
||||
} else {
|
||||
alert("Delete " + name + " successfully!");
|
||||
refreshDirectoryFileList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteFile(file) {
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
fileService.deleteFileIfExists(fileShare, currentPath.join('\\\\'), file, function(error, results) {
|
||||
if (error) {
|
||||
alert("Delete file failed, open brower console for more detailed info.");
|
||||
console.log(error);
|
||||
} else {
|
||||
alert("Delete " + file + " successfully!");
|
||||
refreshDirectoryFileList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createDirectory() {
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
var directoryName = document.getElementById('newdirectory').value;
|
||||
fileService.createDirectoryIfNotExists(fileShare, currentPath.join('\\\\') + '\\' + directoryName, function(error, results) {
|
||||
if (error) {
|
||||
alert("Create directory failed, open brower console for more detailed info.");
|
||||
console.log(error);
|
||||
} else {
|
||||
alert("Create " + directoryName + " successfully!");
|
||||
refreshDirectoryFileList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFileFromStream(checkMD5) {
|
||||
var files = document.getElementById('files').files;
|
||||
if (!files.length) {
|
||||
alert('Please select a file!');
|
||||
return;
|
||||
}
|
||||
var file = files[0];
|
||||
|
||||
var fileService = getFileService();
|
||||
if (!fileService)
|
||||
return;
|
||||
|
||||
var btn = document.getElementById("upload-button");
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = "Uploading";
|
||||
var finishedOrError = false;
|
||||
var fileStream = new FileStream(file);
|
||||
var options = {
|
||||
contentSettings: {
|
||||
contentType: file.type
|
||||
},
|
||||
storeFileContentMD5 : checkMD5
|
||||
};
|
||||
|
||||
var speedSummary = fileService.createFileFromStream(fileShare, currentPath.join('\\\\'), file.name, fileStream, file.size, options, function(error, result, response) {
|
||||
finishedOrError = true;
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = "Upload";
|
||||
if (error) {
|
||||
alert("Upload filed, open brower console for more detailed info.");
|
||||
console.log(error);
|
||||
} else {
|
||||
alert("Upload successfully!");
|
||||
refreshDirectoryFileList();
|
||||
}
|
||||
});
|
||||
|
||||
function refreshProgress() {
|
||||
setTimeout(function() {
|
||||
if (!finishedOrError) {
|
||||
var process = speedSummary.getCompletePercent();
|
||||
document.getElementById("progress").style.width = process + '%';
|
||||
document.getElementById("progress").innerHTML = process + '%';
|
||||
refreshProgress();
|
||||
} else {
|
||||
document.getElementById("progress").style.width = '0%';
|
||||
document.getElementById("progress").innerHTML = '0%';
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
refreshProgress();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,465 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Azure Storage JavaScript Client Library Sample for Queue Operations</title>
|
||||
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="mt-1">
|
||||
<h1>Azure Storage JavaScript Client Library Sample for Queue Operations</h1>
|
||||
</div>
|
||||
<p class="lead">In this sample, we will demonstrate common scenarios for Azure Queue Storage that includes creating, listing and deleting queues and messages.</p>
|
||||
<hr/>
|
||||
|
||||
<p>Azure Storage queue service provides cloud messaging between application components. In designing applications for scale, application components are often decoupled, so that they can scale independently. Queue storage delivers asynchronous messaging for communication between application components, whether they are running in the cloud, on the desktop, on an on-premises server, or on a mobile device. Queue storage also supports managing asynchronous tasks and building process work flows.
|
||||
</p>
|
||||
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Note</b>: You may need set up a HTTP server to host this sample for IE browser, because IndexedDB is only available on websites with http or https URL schemes in IE. Azure Storage JavaScript Client Library currently depends on IndexedDB.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Contents:</h2>
|
||||
<ul>
|
||||
<li><a href="#step1">Step 1: Preparing an Azure Storage account with CORS rules set</a></li>
|
||||
<li><a href="#step2">Step 2: Importing Azure Storage JavaScript Client Library</a></li>
|
||||
<li><a href="#step3">Step 3: Creating an Azure Storage Queue Service Object</a></li>
|
||||
<li><a href="#step4">Step 4: Queue Operations</a></li>
|
||||
<li><a href="#step5">Step 5: Message Operations</a></li>
|
||||
<li><a href="#step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="step1">Step 1: Preparing an Azure Storage account with CORS rules set</h2>
|
||||
<p>Cross-origin resource sharing, or CORS, must be configured on the Azure Storage account to be accessed directly from JavaScript in the browser.
|
||||
You are able to set the CORS rules for specific Azure Storage account on the <a href="https://portal.azure.com">Azure Portal</a>.
|
||||
The "Allowed origins" could be set to "*" to allow all the origins in this sample.
|
||||
For more information about CORS, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services">Cross-Origin Resource Sharing (CORS)</a>.</p>
|
||||
<img src="cors.PNG"/>
|
||||
|
||||
<h2 id="step2">Step 2: Importing Azure Storage JavaScript Client Library</h2>
|
||||
<p>
|
||||
Importing <code>azure-storage.common.js</code> and <code>azure-storage.queue.js</code> in your HTML file for queue operations, and make sure <code>azure-storage.common.js</code> is in front of <code>azure-storage.queue.js</code>.
|
||||
<p>
|
||||
<pre>
|
||||
<script src="azure-storage.common.js"></script>
|
||||
<script src="azure-storage.queue.js"></script>
|
||||
</pre>
|
||||
|
||||
<h2 id="step3">Step 3: Creating an Azure Storage Queue Service Object</h2>
|
||||
<p>
|
||||
The <code>QueueService</code> object lets you work with queues and messages.
|
||||
Following code creates a <code>QueueService</code> object with storage account and SAS Token.
|
||||
</p>
|
||||
<pre>
|
||||
var queueUri = 'https://' + 'STORAGE_ACCOUNT' + '.queue.core.windows.net';
|
||||
var queueService = AzureStorage.createQueueServiceWithSas(queueUri, 'SAS_TOKEN');
|
||||
</pre>
|
||||
<p>
|
||||
In Azure Storage JavaScript Client Library, a global variable <code>AzureStorage</code> is the start point where we can create service objects for blob/table/queue/file and access to the storage utilities.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>How to get full detailed API definitions? </b> Currently, the JavaScript Client Library shares the same API definitions with Node.js SDK.
|
||||
Please check API details on <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js API reference documents</a>. The JavaScript global variable <code>AzureStorage</code> is just like the object <code>require('azure-storage')</code> returns in Node.js.
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Warning</b>: Azure Storage JavaScript Client Library also supports creating <code>QueueService</code> based on Storage Account Key for authentication besides SAS Token.
|
||||
However, for security concerns, we recommend use of a limited time SAS Token, generated by a backend web server using a <a href="https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1">Stored Access Policy</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="step4">Step 4: Queue Operations</h2>
|
||||
<p>
|
||||
Azure Queue storage is a service for storing large numbers of messages that can be accessed from anywhere in the world via authenticated calls using HTTP or HTTPS. A single queue message can be up to 64 KB in size, and a queue can contain millions of messages, up to the total capacity limit of a storage account.
|
||||
</p>
|
||||
|
||||
<h3>List Queues</h3>
|
||||
<p><code>QueueService</code> provides <code>listQueuesSegmented</code> and <code>listQueuesSegmentedWithPrefix</code> for retrieving the queue list under your storage account.</p>
|
||||
<pre>
|
||||
queueService.listQueuesSegmented(null, function (error, results) {
|
||||
if (error) {
|
||||
// List queue error
|
||||
} else {
|
||||
for (var i = 0, queue; queue = results.entries[i]; i++) {
|
||||
// Deal with queue object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Create Queue</h3>
|
||||
<p><code>QueueService</code> provides <code>createQueue</code> and <code>createQueueIfNotExists</code> for creating a queue under a storage account.</p>
|
||||
<pre>
|
||||
queueService.createQueueIfNotExists('myqueue', function(error, result) {
|
||||
if (error) {
|
||||
// Create queue error
|
||||
} else {
|
||||
// Create queue successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Delete Queue</h3>
|
||||
<p><code>QueueService</code> provides <code>deleteQueue</code> and <code>deleteQueueIfExists</code> for deleting a queue under a storage account.</p>
|
||||
<pre>
|
||||
queueService.deleteQueueIfExists('myqueue', function(error, result) {
|
||||
if (error) {
|
||||
// Delete queue error
|
||||
} else {
|
||||
// Delete queue successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3> Executable Example </h3>
|
||||
<p>The sample will try to create an Azure Storage queue service object based on SAS Token authorization. Enter your Azure Storage account name and SAS Token here. Make sure you have set the CORS rules for the Azure Storage queue service, and the SAS Token is in valid period.</p>
|
||||
<label><b>Storage account:</b> </label> <input type="text" id="account"/>
|
||||
<label><b>SAS Token:</b> </label> <input type="text" id="sas"/>
|
||||
<p> Azure Storage queue service provides plenty of interfaces for queue operations. In following example, you can try to list all the queues under your storage account, and try to create or delete one queue from your account.</p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshQueueList()">ListQueues</button> button to view the queue list under your Azure Storage account</p></li>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="createQueue()">CreateQueue</button> button to create a queue under your Azure Storage account:</p>
|
||||
<p><label><b>New Queue Name:</b> </label> <input type="text" value="myqueue" id="newqueue"/> </p>
|
||||
</li>
|
||||
<li><p> Click "<b>Delete</b>" button to delete the queue under your Azure Storage account</p></li>
|
||||
<li><p> Click "<b>Select</b>" button to select a queue and operate with the queue messages in next step</p></li>
|
||||
</ul>
|
||||
<div id="queues"></div>
|
||||
|
||||
<h2 id="step5">Step 5: Message Operations</h2>
|
||||
<p> A storage <b>Message</b>, in any format, of up to 64 KB. The maximum time that a message can remain in the queue is 7 days.</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>Note: </b> Azure Storage JavaScript Client Library provides <code>var encoder = new AzureStorage.QueueMessageEncoder.TextBase64QueueMessageEncoder()</code> which is a Base64 encoder and docoder.
|
||||
If a message content string is encoded with <code>encoder.encode()</code>, remember to decode it with <code>encoder.decode()</code> after peek the message.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Peek Messages</h3>
|
||||
<p><code>QueueService</code> provides <code>peekMessage</code> and <code>peekMessages</code> for retrieving the messages list under a queue.</p>
|
||||
<pre>
|
||||
queueService.peekMessages('myqueue', {numOfMessages: 32}, function (error, results) {
|
||||
if (error) {
|
||||
// Peek messages error
|
||||
} else {
|
||||
for (var i = 0, message; message = results[i]; i++) {
|
||||
// Deal with message object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Create Message</h3>
|
||||
<p><code>QueueService</code> provides <code>createMessage</code> for creating a new message to a queue.</p>
|
||||
<pre>
|
||||
var encoder = new AzureStorage.QueueMessageEncoder.TextBase64QueueMessageEncoder();
|
||||
queueService.createMessage('myqueue', encoder.encode('mymessage'), function (error, results, response) {
|
||||
if (error) {
|
||||
// Create message error
|
||||
} else {
|
||||
// Create message successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Dequeue Message</h3>
|
||||
<p><code>QueueService</code> provides <code>getMessages</code> and <code>deleteMessage</code> for dequeuing next message in a queue.</p>
|
||||
<pre>
|
||||
queueService.getMessages('myqueue', function(error, result, response) {
|
||||
if(!error){
|
||||
// Message text is in messages[0].messageText
|
||||
var message = result[0];
|
||||
queueService.deleteMessage('myqueue', message.messageId, message.popReceipt, function(error, response){
|
||||
if(!error){
|
||||
//message deleted
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Update Message</h3>
|
||||
<p><code>QueueService</code> provides <code>getMessages</code> and <code>updateMessage</code> for updating next message in a queue.</p>
|
||||
<pre>
|
||||
var encoder = new AzureStorage.QueueMessageEncoder.TextBase64QueueMessageEncoder();
|
||||
queueService.getMessages('myqueue', function(error, result, response) {
|
||||
if(!error){
|
||||
// Got the message
|
||||
var message = result[0];
|
||||
queueService.updateMessage('myqueue', message.messageId, message.popReceipt, 10, {messageText: encoder.encode('new text')}, function(error, result, response){
|
||||
if(!error){
|
||||
// Message updated successfully
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3> Executable Example </h3>
|
||||
<p>After clicked the "<b>Select</b>" button on the queue list in last step, you are able to operate with the queue messages under the selected queue.<p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshMessageList()">PeekMessages</button> button to refresh the message list in your selected queue</p></li>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="addMessage()">AddMessage</button> button to create a message in your selected queue: </p>
|
||||
<p><label><b>New Message Content:</b> </label> <input type="text" value="Message Content" id="newmessage"/> </p>
|
||||
</li>
|
||||
<li><p> Click <button class="btn btn-xs btn-success" onclick="update()">Update</button> button to update the top queue message in your selected queue (Dequeued messages will be invisible for 30s by default.):</p>
|
||||
<p><label><b>Update Message Content:</b> </label> <input type="text" value="Updated Message Content" id="updatemessage"/> </p>
|
||||
</li>
|
||||
<li><p> Click <button class="btn btn-xs btn-danger" onclick="dequeue()">Dequeue</button> button to dequeue the top queue message in your selected queue:</p></li>
|
||||
</ul>
|
||||
|
||||
<div id="result"></div>
|
||||
|
||||
<h2 id="step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</h2>
|
||||
<ul>
|
||||
<li>1. Setting CORS rules for your selected Azure-Storage account queue service.</li>
|
||||
<li>2. Including "azure-storage.common.js" in the html file.</li>
|
||||
<li>3. Including functional file(s) needed, such as "azure-storage.queue.js" for queue operation.</li>
|
||||
<li>4. Using keyword "AzureStorage" to access to Azure storage JavaScript APIs.</li>
|
||||
<li>5. Referring to <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js SDK documents</a> for detailed API definitions which keep same with JavaScript APIs.</li>
|
||||
</ul>
|
||||
<p> You can view the source code of this sample for detailed reference. </p>
|
||||
</div>
|
||||
|
||||
<!-- azure-storage.common.js also exports Node.js module stream, util and buffer -->
|
||||
<script src="../bundle/azure-storage.common.js"></script>
|
||||
<script src="../bundle/azure-storage.queue.js"></script>
|
||||
<script>
|
||||
var account = document.getElementById('account').value;
|
||||
var sas = document.getElementById('sas').value;
|
||||
var queue = '';
|
||||
var queueUri = '';
|
||||
var encoder = new AzureStorage.QueueMessageEncoder.TextBase64QueueMessageEncoder();
|
||||
|
||||
function checkParameters() {
|
||||
account = document.getElementById('account').value;
|
||||
sas = document.getElementById('sas').value;
|
||||
|
||||
if (account == null || account.length < 1)
|
||||
{
|
||||
alert('Please enter a valid storage account name!');
|
||||
return false;
|
||||
}
|
||||
if (sas == null || sas.length < 1)
|
||||
{
|
||||
alert('Please enter a valid SAS Token!');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getQueueService() {
|
||||
if (!checkParameters())
|
||||
return null;
|
||||
|
||||
queueUri = 'https://' + account + '.queue.core.windows.net';
|
||||
var queueService = AzureStorage.createQueueServiceWithSas(queueUri, sas).withFilter(new AzureStorage.ExponentialRetryPolicyFilter());
|
||||
return queueService;
|
||||
}
|
||||
|
||||
function refreshQueueList()
|
||||
{
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
document.getElementById('queues').innerHTML = 'Loading queue list...';
|
||||
queueService.listQueuesSegmented(null, {maxResults : 200}, function(error, results) {
|
||||
if (error) {
|
||||
alert('List queue list error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>QueueName</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
|
||||
if (results.entries.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
|
||||
for (var i = 0, queue; queue = results.entries[i]; i++) {
|
||||
output.push('<tr>',
|
||||
'<td>', queue.name, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteQueue(\'', queue.name ,'\')">Delete</button> ',
|
||||
'<button class="btn btn-xs btn-success" onclick="viewQueue(\'', queue.name ,'\')">Select</button>', '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('queues').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createQueue() {
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
var queue = document.getElementById('newqueue').value;
|
||||
if (!AzureStorage.Validate.queueNameIsValid(queue, function(err, res){})) {
|
||||
alert('Invalid queue name!');
|
||||
return;
|
||||
}
|
||||
queueService.createQueueIfNotExists(queue.toLowerCase(), function(error, result) {
|
||||
if (error) {
|
||||
alert('Create queue failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Create ' + queue + ' successfully!');
|
||||
refreshQueueList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteQueue(queue) {
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
queueService.deleteQueueIfExists(queue, function(error, result) {
|
||||
if (error) {
|
||||
alert('Delete queue failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete ' + queue + ' successfully!');
|
||||
refreshQueueList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function viewQueue(selectedQueue) {
|
||||
queue = selectedQueue;
|
||||
alert('Selected ' + queue + ' !');
|
||||
refreshMessageList();
|
||||
}
|
||||
|
||||
function refreshMessageList() {
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
if (queue == null || queue.length < 1) {
|
||||
alert('Please select a queue from queue list!')
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('result').innerHTML = 'Loading queue messages...';
|
||||
queueService.peekMessages(queue, {numOfMessages: 32}, function (error, results) {
|
||||
if (error) {
|
||||
alert('List queue messages error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>MessageId</th>',
|
||||
'<th>MessageContent</th>',
|
||||
'<th>DequeueCount</th>',
|
||||
'<th>InsertionTime</th>',
|
||||
'</tr>');
|
||||
if (results.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, message; message = results[i]; i++) {
|
||||
output.push('<tr>',
|
||||
'<td>', message.messageId, '</td>',
|
||||
'<td>', encoder.decode(message.messageText), '</td>',
|
||||
'<td>', message.dequeueCount, '</td>',
|
||||
'<td>', message.insertionTime, '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('result').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addMessage() {
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
if (queue == null || queue.length < 1) {
|
||||
alert('Please select a queue from queue list!')
|
||||
return;
|
||||
}
|
||||
|
||||
var message = document.getElementById('newmessage').value;
|
||||
queueService.createMessage(queue, encoder.encode(message), function(error, result, response) {
|
||||
if(error) {
|
||||
alert('Create messages error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Create message successfully!');
|
||||
refreshMessageList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dequeue() {
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
if (queue == null || queue.length < 1) {
|
||||
alert('Please select a queue from queue list!')
|
||||
return;
|
||||
}
|
||||
|
||||
queueService.getMessages(queue, function(error, result, response) {
|
||||
if(!error) {
|
||||
if (result.length < 1)
|
||||
return;
|
||||
|
||||
var message = result[0];
|
||||
queueService.deleteMessage(queue, message.messageId, message.popReceipt, function(error, response) {
|
||||
if(error) {
|
||||
alert('Delete message error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete message successfully!');
|
||||
refreshMessageList();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function update() {
|
||||
var queueService = getQueueService();
|
||||
if (!queueService)
|
||||
return;
|
||||
|
||||
if (queue == null || queue.length < 1) {
|
||||
alert('Please select a queue from queue list!')
|
||||
return;
|
||||
}
|
||||
|
||||
var updateMessage = document.getElementById("updatemessage").value;
|
||||
queueService.getMessages(queue, function(error, result, response) {
|
||||
if(!error) {
|
||||
if (result.length < 1)
|
||||
return;
|
||||
|
||||
var message = result[0];
|
||||
queueService.updateMessage(queue, message.messageId, message.popReceipt, 10, {messageText: encoder.encode(updateMessage)}, function(error, result, response){
|
||||
if(error) {
|
||||
alert('Update message error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Update message successfully!');
|
||||
refreshMessageList();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,440 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Azure Storage JavaScript Client Library Sample for Table Operations</title>
|
||||
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="mt-1">
|
||||
<h1>Azure Storage JavaScript Client Library Sample for Table Operations</h1>
|
||||
</div>
|
||||
<p class="lead">In this sample, we will demonstrate common scenarios for Azure Table Storage that includes creating, listing and deleting tables and entities.</p>
|
||||
<hr/>
|
||||
|
||||
<p>Azure Storage table is a service that stores structured NoSQL data in the cloud. Table storage is a key/attribute store with a schemaless design. Because Table storage is schemaless, it's easy to adapt your data as the needs of your application evolve. Access to data is fast and cost-effective for all kinds of applications. Table storage is typically significantly lower in cost than traditional SQL for similar volumes of data.
|
||||
</p>
|
||||
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Note</b>: You may need set up a HTTP server to host this sample for IE browser, because IndexedDB is only available on websites with http or https URL schemes in IE. Azure Storage JavaScript Client Library currently depends on IndexedDB.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Contents:</h2>
|
||||
<ul>
|
||||
<li><a href="#step1">Step 1: Preparing an Azure Storage account with CORS rules set</a></li>
|
||||
<li><a href="#step2">Step 2: Importing Azure Storage JavaScript Client Library</a></li>
|
||||
<li><a href="#step3">Step 3: Creating an Azure Storage Table Service Object</a></li>
|
||||
<li><a href="#step4">Step 4: Table Operations</a></li>
|
||||
<li><a href="#step5">Step 5: Table Entities Operations</a></li>
|
||||
<li><a href="#step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="step1">Step 1: Preparing an Azure Storage account with CORS rules set</h2>
|
||||
<p>Cross-origin resource sharing, or CORS, must be configured on the Azure Storage account to be accessed directly from JavaScript in the browser.
|
||||
You are able to set the CORS rules for specific Azure Storage account on the <a href="https://portal.azure.com">Azure Portal</a>.
|
||||
The "Allowed origins" could be set to "*" to allow all the origins in this sample.
|
||||
For more information about CORS, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services">Cross-Origin Resource Sharing (CORS)</a>.</p>
|
||||
<img src="cors.PNG"/>
|
||||
|
||||
<h2 id="step2">Step 2: Importing Azure Storage JavaScript Client Library</h2>
|
||||
<p>
|
||||
Importing <code>azure-storage.common.js</code> and <code>azure-storage.table.js</code> in your HTML file for table operations, and make sure <code>azure-storage.common.js</code> is in front of <code>azure-storage.table.js</code>.
|
||||
<p>
|
||||
<pre>
|
||||
<script src="azure-storage.common.js"></script>
|
||||
<script src="azure-storage.table.js"></script>
|
||||
</pre>
|
||||
|
||||
<h2 id="step3">Step 3: Creating an Azure Storage Table Service Object</h2>
|
||||
<p>
|
||||
The <code>TableService</code> object lets you work with table and entities.
|
||||
Following code creates a <code>TableService</code> object with storage account and SAS Token.
|
||||
</p>
|
||||
<pre>
|
||||
var tableUri = 'https://' + 'STORAGE_ACCOUNT' + '.table.core.windows.net';
|
||||
var tableService = AzureStorage.createTableServiceWithSas(tableUri, 'SAS_TOKEN');
|
||||
</pre>
|
||||
<p>
|
||||
In Azure Storage JavaScript Client Library, a global variable <code>AzureStorage</code> is the start point where we can create service objects for blob/table/queue/file and access to the storage utilities.
|
||||
</p>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-body">
|
||||
<b>How to get full detailed API definitions? </b> Currently, the JavaScript Client Library shares the same API definitions with Node.js SDK.
|
||||
Please check API details on <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js API reference documents</a>. The JavaScript global variable <code>AzureStorage</code> is just like the object <code>require('azure-storage')</code> returns in Node.js.
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-body">
|
||||
<b>Warning</b>: Azure Storage JavaScript Client Library also supports creating <code>TableService</code> based on Storage Account Key for authentication besides SAS Token.
|
||||
However, for security concerns, we recommend use of a limited time SAS Token, generated by a backend web server using a <a href="https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1">Stored Access Policy</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="step4">Step 4: Table Operations</h2>
|
||||
<p>
|
||||
<b>Table</b>: A table is a collection of entities. Tables don't enforce a schema on entities, which means a single table can contain entities that have different sets of properties. The number of tables that a storage account can contain is limited only by the storage account capacity limit.
|
||||
</p>
|
||||
|
||||
<h3>List Tables</h3>
|
||||
<p><code>TableService</code> provides <code>listTablesSegmented</code> and <code>listTablesSegmentedWithPrefix</code> for retrieving the table list under your storage account.</p>
|
||||
<pre>
|
||||
tableService.listTablesSegmented(null, {maxResults : 200}, function (error, results) {
|
||||
if (error) {
|
||||
// List tables error
|
||||
} else {
|
||||
for (var i = 0, table; table = results.entries[i]; i++) {
|
||||
// Deal with table object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Create Table</h3>
|
||||
<p><code>TableService</code> provides <code>createTable</code> and <code>createTableIfNotExists</code> for creating a table under a storage account.</p>
|
||||
<pre>
|
||||
tableService.createTableIfNotExists('mytable', function(error, result) {
|
||||
if (error) {
|
||||
// Create table error
|
||||
} else {
|
||||
// Create table successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Delete Table</h3>
|
||||
<p><code>TableService</code> provides <code>deleteTable</code> and <code>deleteTableIfExists</code> for deleting a table under a storage account.</p>
|
||||
<pre>
|
||||
tableService.deleteTableIfExists('mytable', function(error, result) {
|
||||
if (error) {
|
||||
// Delete table error
|
||||
} else {
|
||||
// Delete table successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3> Executable Example </h3>
|
||||
<p>The sample will try to create an Azure Storage table service object based on SAS Token authorization. Enter your Azure Storage account name and SAS Token here. Make sure you have set the CORS rules for the Azure Storage table service, and the SAS Token is in valid period.</p>
|
||||
<label><b>Storage account:</b> </label> <input type="text" id="account"/>
|
||||
<label><b>SAS Token:</b> </label> <input type="text" id="sas"/>
|
||||
<p> Azure Storage table service provides plenty of interfaces for table operations. In following example, you can try to list all the tables under your storage account, and try to create or delete one table from your account.</p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshTableList()">ListTables</button> button to view the table list under your Azure Storage account</p></li>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="createTable()">CreateTable</button> button to create a table under your Azure Storage account</p>
|
||||
<p><label><b>New Table Name:</b> </label> <input type="text" value="mytable" id="newtable"/> </p>
|
||||
</li>
|
||||
<li><p> Click "<b>Delete</b>" button to delete the table under your Azure Storage account</p></li>
|
||||
<li><p> Click "<b>Select</b>" button to operate with the table entities in next step</p></li>
|
||||
</ul>
|
||||
<div id="tables"></div>
|
||||
|
||||
<h2 id="step5">Step 5: Table Entities Operations</h2>
|
||||
<p><b>Entity</b>: An entity is a set of properties, similar to a database row. An entity can be up to 1MB in size.</p>
|
||||
<p><b>Properties</b>: A property is a name-value pair. Each entity can include up to 252 properties to store data. Each entity also has 3 system properties that specify a partition key, a row key, and a timestamp. Entities with the same partition key can be queried more quickly, and inserted/updated in atomic operations. An entity's row key is its unique identifier within a partition.</p>
|
||||
|
||||
<h3>Query Entities</h3>
|
||||
<p><code>TableService</code> provides <code>queryEntities</code> for querying a table under a storage account.</p>
|
||||
<pre>
|
||||
var tableQuery = new AzureStorage.TableQuery().top(200);
|
||||
tableService.queryEntities('mytable', tableQuery, null, function(error, result) {
|
||||
if (error) {
|
||||
// Query entities error
|
||||
} else {
|
||||
for (var i = 0, entity; entity = results.entries[i]; i++) {
|
||||
// Deal with entity object
|
||||
}
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Insert or Replace Entity</h3>
|
||||
<p><code>TableService</code> provides <code>insertEntity</code>, <code>insertOrReplaceEntity</code> and <code>insertOrMergeEntity</code> for adding a table entity under a storage account.</p>
|
||||
<pre>
|
||||
var insertEntity = {
|
||||
PartitionKey: {'_': 'partitionKey'},
|
||||
RowKey: {'_': 'rowKey'}
|
||||
};
|
||||
|
||||
tableService.insertOrReplaceEntity('mytable', insertEntity, function(error, result, response) {
|
||||
if(error) {
|
||||
// Insert table entity error
|
||||
} else {
|
||||
// Insert table entity successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3>Delete Entity</h3>
|
||||
<p><code>TableService</code> provides <code>deleteEntity</code> for deleting a table entity under a storage account.</p>
|
||||
<pre>
|
||||
var deleteEntity = {
|
||||
PartitionKey: {'_': 'partitionKey'},
|
||||
RowKey: {'_': 'rowKey'}
|
||||
};
|
||||
|
||||
tableService.deleteEntity('mytable', deleteEntity, function(error, result, response) {
|
||||
if(error) {
|
||||
// Delete table entity error
|
||||
} else {
|
||||
// Delete table entity successfully
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h3> Executable Example </h3>
|
||||
<p>After clicked the "<b>Select</b>" button on the table list, you are able to operate with the table entities under the selected table.<p>
|
||||
<ul>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="refreshEntityList()">QueryEntities</button> button to refresh the entity list in your selected table</p></li>
|
||||
<li><p> Click <button class="btn btn-xs btn-primary" onclick="addEntity()">AddOrUpdateEntity</button> button to create an entity in your selected table. If existing entity with the sampe PartitionKey and RowKey, old entity will be merged.</p>
|
||||
<p>
|
||||
<label><b>PK</b> </label> <input type="text" value="PartitionKey" id="pk"/>
|
||||
<label><b>RK</b> </label> <input type="text" value="RowKey" id="rk"/>
|
||||
<label><b>CustomProperty1</b> </label> <input type="text" value="Custom Property 1" id="cp1"/>
|
||||
<label><b>CustomProperty2</b> </label> <input type="text" value="Custom Property 2" id="cp2"/>
|
||||
</p>
|
||||
</li>
|
||||
<li><p> Click "<b>Delete</b>" button to delete the selected table entity in your selected table</p></li>
|
||||
</ul>
|
||||
<div id="result"></div>
|
||||
|
||||
<h3 id="step6">Step 6: Creating your JavaScript Application based on Azure Storage JavaScript Client Library</h3>
|
||||
<ul>
|
||||
<li>1. Setting CORS rules for your selected Azure-Storage account table service.</li>
|
||||
<li>2. Including "azure-storage.common.js" in the html file.</li>
|
||||
<li>3. Including functional file(s) needed, such as "azure-storage.table.js" for table operation.</li>
|
||||
<li>4. Using keyword "AzureStorage" to access to Azure storage JavaScript APIs.</li>
|
||||
<li>5. Referring to <a href="http://azure.github.io/azure-storage-node/">Azure Storage Node.js SDK documents</a> for detailed API definitions which keep same with JavaScript APIs.</li>
|
||||
</ul>
|
||||
<p> You can view the source code of this sample for detailed reference. </p>
|
||||
</div>
|
||||
|
||||
<!-- azure-storage.common.js also exports Node.js module stream, util and buffer -->
|
||||
<script src="../bundle/azure-storage.common.js"></script>
|
||||
<script src="../bundle/azure-storage.table.js"></script>
|
||||
|
||||
<script>
|
||||
var account = document.getElementById('account').value;
|
||||
var sas = document.getElementById('sas').value;
|
||||
var table = '';
|
||||
var tableUri = '';
|
||||
|
||||
function checkParameters() {
|
||||
account = document.getElementById('account').value;
|
||||
sas = document.getElementById('sas').value;
|
||||
|
||||
if (account == null || account.length < 1)
|
||||
{
|
||||
alert('Please enter a valid storage account name!');
|
||||
return false;
|
||||
}
|
||||
if (sas == null || sas.length < 1)
|
||||
{
|
||||
alert('Please enter a valid SAS Token!');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTableService() {
|
||||
if (!checkParameters())
|
||||
return null;
|
||||
|
||||
tableUri = 'https://' + account + '.table.core.windows.net';
|
||||
var tableService = AzureStorage.createTableServiceWithSas(tableUri, sas).withFilter(new AzureStorage.ExponentialRetryPolicyFilter());
|
||||
return tableService;
|
||||
}
|
||||
|
||||
function refreshTableList()
|
||||
{
|
||||
var tableService = getTableService();
|
||||
if (!tableService)
|
||||
return;
|
||||
|
||||
document.getElementById('tables').innerHTML = 'Loading table list...';
|
||||
tableService.listTablesSegmented(null, {maxResults : 200}, function(error, results) {
|
||||
if (error) {
|
||||
alert('List table list error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>TableName</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
if (results.entries.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, table; table = results.entries[i]; i++) {
|
||||
output.push('<tr>',
|
||||
'<td>', table, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteTable(\'', table ,'\')">Delete</button> ',
|
||||
'<button class="btn btn-xs btn-success" onclick="viewTable(\'', table ,'\')">Select</button>', '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('tables').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createTable() {
|
||||
var tableService = getTableService();
|
||||
if (!tableService)
|
||||
return;
|
||||
|
||||
var table = document.getElementById('newtable').value;
|
||||
if (!AzureStorage.Validate.tableNameIsValid(table, function(err, res){})) {
|
||||
alert('Invalid table name!');
|
||||
return;
|
||||
}
|
||||
tableService.createTableIfNotExists(table.toLowerCase(), function(error, result) {
|
||||
if (error) {
|
||||
alert('Create table failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Create ' + table + ' successfully!');
|
||||
refreshTableList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteTable(table) {
|
||||
var tableService = getTableService();
|
||||
if (!tableService)
|
||||
return;
|
||||
|
||||
tableService.deleteTableIfExists(table, function(error, result) {
|
||||
if (error) {
|
||||
alert('Delete table failed, open brower console for more detailed info.');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete ' + table + ' successfully!');
|
||||
refreshTableList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function viewTable(selectedTable) {
|
||||
table = selectedTable;
|
||||
alert('Selected ' + table + ' !');
|
||||
refreshEntityList();
|
||||
}
|
||||
|
||||
function refreshEntityList() {
|
||||
var tableService = getTableService();
|
||||
if (!tableService)
|
||||
return;
|
||||
|
||||
if (table == null || table.length < 1) {
|
||||
alert('Please select a table from table list!')
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('result').innerHTML = 'Loading table entities...';
|
||||
var tableQuery = new AzureStorage.TableQuery().top(200);
|
||||
tableService.queryEntities(table, tableQuery, null, function(error, results) {
|
||||
if (error) {
|
||||
alert('List table entities error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
var output = [];
|
||||
output.push('<tr>',
|
||||
'<th>PartitionKey</th>',
|
||||
'<th>RowKey</th>',
|
||||
'<th>Custom Property 1</th>',
|
||||
'<th>Custom Property 2</th>',
|
||||
'<th>Timestamp</th>',
|
||||
'<th>Operations</th>',
|
||||
'</tr>');
|
||||
if (results.entries.length < 1) {
|
||||
output.push('<tr><td>Empty results...</td></tr>');
|
||||
}
|
||||
for (var i = 0, entity; entity = results.entries[i]; i++) {
|
||||
var cp1 = '';
|
||||
var cp2 = '';
|
||||
|
||||
if (typeof entity.CustomProperty1 !== 'undefined') {
|
||||
cp1 = entity.CustomProperty1._;
|
||||
}
|
||||
if (typeof entity.CustomProperty2 !== 'undefined') {
|
||||
cp2 = entity.CustomProperty2._;
|
||||
}
|
||||
|
||||
output.push('<tr>',
|
||||
'<td>', entity.PartitionKey._, '</td>',
|
||||
'<td>', entity.RowKey._, '</td>',
|
||||
'<td>', cp1, '</td>',
|
||||
'<td>', cp2, '</td>',
|
||||
'<td>', entity.Timestamp._, '</td>',
|
||||
'<td>', '<button class="btn btn-xs btn-danger" onclick="deleteEntity(\'', entity.PartitionKey._ ,'\'', ',', '\'', entity.RowKey._ ,'\'',')">Delete</button>', '</td>',
|
||||
'</tr>');
|
||||
}
|
||||
document.getElementById('result').innerHTML = '<table class="table table-condensed table-bordered">' + output.join('') + '</table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addEntity() {
|
||||
var tableService = getTableService();
|
||||
if (!tableService)
|
||||
return;
|
||||
|
||||
if (table == null || table.length < 1) {
|
||||
alert('Invalid table name!')
|
||||
return;
|
||||
}
|
||||
|
||||
var partitionKey = document.getElementById('pk').value;
|
||||
var rowKey = document.getElementById('rk').value;
|
||||
var customProperty1 = document.getElementById('cp1').value;
|
||||
var customProperty2 = document.getElementById('cp2').value;
|
||||
var insertEntity = {
|
||||
PartitionKey: {'_': partitionKey},
|
||||
RowKey: {'_': rowKey},
|
||||
CustomProperty1: {'_': customProperty1},
|
||||
CustomProperty2: {'_': customProperty2}
|
||||
};
|
||||
|
||||
tableService.insertOrMergeEntity(table, insertEntity, function(error, result, response) {
|
||||
if(error) {
|
||||
alert('Insert table entity error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Insert table entity successfully!');
|
||||
refreshEntityList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteEntity(partitionKey, rowKey) {
|
||||
var tableService = getTableService();
|
||||
if (!tableService)
|
||||
return;
|
||||
|
||||
if (table == null || table.length < 1) {
|
||||
alert('Invalid table name!')
|
||||
return;
|
||||
}
|
||||
|
||||
var deleteEntity = {
|
||||
PartitionKey: {'_': partitionKey},
|
||||
RowKey: {'_': rowKey}
|
||||
};
|
||||
|
||||
tableService.deleteEntity(table, deleteEntity, function(error, result, response) {
|
||||
if(error) {
|
||||
alert('Delete table entity error, please open browser console to view detailed error');
|
||||
console.log(error);
|
||||
} else {
|
||||
alert('Delete table entity successfully!');
|
||||
refreshEntityList();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -34,9 +34,11 @@
|
|||
"md5.js": "1.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "^13.3.0",
|
||||
"browserify-fs": "^1.0.0",
|
||||
"batchflow": "0.4.0",
|
||||
"coveralls": "^2.11.4",
|
||||
"factor-bundle": "^2.5.0",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-contrib-jshint": "~0.11.0",
|
||||
"grunt-devserver": "^0.6.0",
|
||||
|
@ -69,6 +71,7 @@
|
|||
"test": "jshint lib && nsp check && mocha --no-timeouts --recursive test",
|
||||
"testwithoutcheck": "jshint lib && mocha --no-timeouts --recursive test",
|
||||
"cover": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec -u bdd --no-timeouts --recursive test",
|
||||
"coveralls": "npm run cover && cat ./coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js"
|
||||
"coveralls": "npm run cover && cat ./coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js",
|
||||
"genjs": "node ./browser/bundle.js"
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче