Azure云服务
📖 概述
Microsoft Azure 是微软的云计算平台,提供超过200种服务,包括计算、存储、网络、数据库、AI和机器学习等。本文档将详细介绍如何在Node.js应用中集成各种Azure服务。
🎯 学习目标
- 掌握Azure SDK的使用方法
- 学习核心Azure服务的集成
- 了解Azure服务的最佳实践
- 实现安全的Azure服务访问
🔧 环境准备
1. 安装Azure SDK
bash
# Azure核心库
npm install @azure/identity @azure/core-auth
# 存储服务
npm install @azure/storage-blob @azure/storage-queue
# 数据库服务
npm install @azure/cosmos @azure/data-tables
# 消息服务
npm install @azure/service-bus @azure/event-hubs
# AI服务
npm install @azure/cognitiveservices-textanalytics @azure/openai
# 函数和应用服务
npm install @azure/functions-core @azure/app-configuration
2. 身份验证配置
javascript
const { DefaultAzureCredential, ClientSecretCredential } = require('@azure/identity');
// 方法1: 默认凭据链 (推荐)
const credential = new DefaultAzureCredential();
// 方法2: 服务主体认证
const credential2 = new ClientSecretCredential(
process.env.AZURE_TENANT_ID,
process.env.AZURE_CLIENT_ID,
process.env.AZURE_CLIENT_SECRET
);
// 方法3: 环境变量配置
/*
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
AZURE_SUBSCRIPTION_ID=your-subscription-id
*/
🗄️ Blob Storage 对象存储
1. 基本操作
javascript
const { BlobServiceClient } = require('@azure/storage-blob');
const { DefaultAzureCredential } = require('@azure/identity');
class AzureBlobService {
constructor() {
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const credential = new DefaultAzureCredential();
this.blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
credential
);
this.containerName = process.env.AZURE_CONTAINER_NAME;
}
// 上传文件
async uploadFile(fileName, fileBuffer, options = {}) {
try {
const containerClient = this.blobServiceClient.getContainerClient(this.containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
const uploadResponse = await blockBlobClient.upload(fileBuffer, fileBuffer.length, {
blobHTTPHeaders: {
blobContentType: options.contentType || 'application/octet-stream',
},
metadata: options.metadata || {},
tags: options.tags || {},
});
return {
success: true,
etag: uploadResponse.etag,
lastModified: uploadResponse.lastModified,
url: blockBlobClient.url,
};
} catch (error) {
throw new Error(`上传失败: ${error.message}`);
}
}
// 下载文件
async downloadFile(fileName) {
try {
const containerClient = this.blobServiceClient.getContainerClient(this.containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
const downloadResponse = await blockBlobClient.download();
return downloadResponse.readableStreamBody;
} catch (error) {
throw new Error(`下载失败: ${error.message}`);
}
}
// 生成SAS URL
async generateSasUrl(fileName, permissions = 'r', expiryMinutes = 60) {
const { generateBlobSASQueryParameters, BlobSASPermissions } = require('@azure/storage-blob');
const containerClient = this.blobServiceClient.getContainerClient(this.containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
const expiresOn = new Date();
expiresOn.setMinutes(expiresOn.getMinutes() + expiryMinutes);
const sasOptions = {
containerName: this.containerName,
blobName: fileName,
permissions: BlobSASPermissions.parse(permissions),
expiresOn,
};
const sasToken = generateBlobSASQueryParameters(
sasOptions,
this.blobServiceClient.credential
).toString();
return `${blockBlobClient.url}?${sasToken}`;
}
// 列出文件
async listFiles(prefix = '') {
try {
const containerClient = this.blobServiceClient.getContainerClient(this.containerName);
const files = [];
for await (const blob of containerClient.listBlobsFlat({ prefix })) {
files.push({
name: blob.name,
size: blob.properties.contentLength,
lastModified: blob.properties.lastModified,
contentType: blob.properties.contentType,
});
}
return files;
} catch (error) {
throw new Error(`列出文件失败: ${error.message}`);
}
}
// 删除文件
async deleteFile(fileName) {
try {
const containerClient = this.blobServiceClient.getContainerClient(this.containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
await blockBlobClient.delete();
return { success: true };
} catch (error) {
throw new Error(`删除失败: ${error.message}`);
}
}
}
// 使用示例
const blobService = new AzureBlobService();
app.post('/upload', upload.single('file'), async (req, res) => {
try {
const fileName = `${Date.now()}-${req.file.originalname}`;
const result = await blobService.uploadFile(fileName, req.file.buffer, {
contentType: req.file.mimetype,
metadata: { uploadedBy: req.user.id },
});
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
2. 高级功能
javascript
// 大文件分块上传
class AzureBlobAdvanced extends AzureBlobService {
async uploadLargeFile(fileName, fileStream, fileSize, options = {}) {
const containerClient = this.blobServiceClient.getContainerClient(this.containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
const blockSize = 4 * 1024 * 1024; // 4MB blocks
const blockIds = [];
try {
let offset = 0;
let blockIndex = 0;
while (offset < fileSize) {
const blockId = Buffer.from(`block-${blockIndex.toString().padStart(6, '0')}`).toString('base64');
const blockSize2 = Math.min(blockSize, fileSize - offset);
await blockBlobClient.stageBlock(blockId, fileStream, blockSize2);
blockIds.push(blockId);
offset += blockSize2;
blockIndex++;
}
// 提交所有块
await blockBlobClient.commitBlockList(blockIds, {
blobHTTPHeaders: {
blobContentType: options.contentType,
},
});
return { success: true, blockCount: blockIds.length };
} catch (error) {
throw new Error(`大文件上传失败: ${error.message}`);
}
}
}
🗃️ Cosmos DB 数据库
1. 基本操作
javascript
const { CosmosClient } = require('@azure/cosmos');
class CosmosDBService {
constructor() {
this.client = new CosmosClient({
endpoint: process.env.COSMOS_DB_ENDPOINT,
key: process.env.COSMOS_DB_KEY,
});
this.databaseId = process.env.COSMOS_DB_DATABASE;
this.containerId = process.env.COSMOS_DB_CONTAINER;
}
async getContainer() {
const database = this.client.database(this.databaseId);
return database.container(this.containerId);
}
// 创建文档
async createDocument(document) {
try {
const container = await this.getContainer();
const { resource } = await container.items.create({
...document,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});
return resource;
} catch (error) {
throw new Error(`创建文档失败: ${error.message}`);
}
}
// 获取文档
async getDocument(id, partitionKey) {
try {
const container = await this.getContainer();
const { resource } = await container.item(id, partitionKey).read();
return resource;
} catch (error) {
if (error.code === 404) {
return null;
}
throw new Error(`获取文档失败: ${error.message}`);
}
}
// 更新文档
async updateDocument(id, partitionKey, updates) {
try {
const container = await this.getContainer();
const { resource: existingDoc } = await container.item(id, partitionKey).read();
const updatedDoc = {
...existingDoc,
...updates,
updatedAt: new Date().toISOString(),
};
const { resource } = await container.item(id, partitionKey).replace(updatedDoc);
return resource;
} catch (error) {
throw new Error(`更新文档失败: ${error.message}`);
}
}
// 查询文档
async queryDocuments(querySpec, options = {}) {
try {
const container = await this.getContainer();
const { resources } = await container.items.query(querySpec, options).fetchAll();
return resources;
} catch (error) {
throw new Error(`查询文档失败: ${error.message}`);
}
}
// 删除文档
async deleteDocument(id, partitionKey) {
try {
const container = await this.getContainer();
await container.item(id, partitionKey).delete();
return { success: true };
} catch (error) {
throw new Error(`删除文档失败: ${error.message}`);
}
}
}
// 使用示例
const cosmosService = new CosmosDBService();
app.post('/users', async (req, res) => {
try {
const user = await cosmosService.createDocument({
id: req.body.id,
email: req.body.email,
name: req.body.name,
partitionKey: req.body.email, // 使用email作为分区键
});
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.get('/users/search', async (req, res) => {
try {
const querySpec = {
query: 'SELECT * FROM c WHERE CONTAINS(c.name, @searchTerm)',
parameters: [
{ name: '@searchTerm', value: req.query.q }
],
};
const users = await cosmosService.queryDocuments(querySpec);
res.json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
2. 批量操作和事务
javascript
class CosmosDBBatchService extends CosmosDBService {
// 批量操作
async batchOperations(operations) {
try {
const container = await this.getContainer();
const { resources } = await container.items.batch(operations);
return resources;
} catch (error) {
throw new Error(`批量操作失败: ${error.message}`);
}
}
// 事务操作
async transactionalBatch(partitionKey, operations) {
try {
const container = await this.getContainer();
const { resources } = await container.items.batch(operations, partitionKey);
return resources;
} catch (error) {
throw new Error(`事务操作失败: ${error.message}`);
}
}
}
// 使用示例
const batchOperations = [
{
operationType: 'Create',
resourceBody: { id: '1', name: 'User 1', partitionKey: 'users' }
},
{
operationType: 'Create',
resourceBody: { id: '2', name: 'User 2', partitionKey: 'users' }
},
{
operationType: 'Upsert',
resourceBody: { id: '3', name: 'User 3', partitionKey: 'users' }
}
];
await cosmosService.batchOperations(batchOperations);
🚌 Service Bus 消息服务
1. 队列操作
javascript
const { ServiceBusClient } = require('@azure/service-bus');
class ServiceBusService {
constructor() {
this.client = new ServiceBusClient(
process.env.SERVICE_BUS_CONNECTION_STRING
);
}
// 发送消息到队列
async sendToQueue(queueName, messages) {
const sender = this.client.createSender(queueName);
try {
if (Array.isArray(messages)) {
await sender.sendMessages(messages);
} else {
await sender.sendMessages([messages]);
}
return { success: true };
} catch (error) {
throw new Error(`发送消息失败: ${error.message}`);
} finally {
await sender.close();
}
}
// 接收队列消息
async receiveFromQueue(queueName, maxMessages = 10) {
const receiver = this.client.createReceiver(queueName);
try {
const messages = await receiver.receiveMessages(maxMessages, {
maxWaitTimeInMs: 60000, // 60秒
});
const results = [];
for (const message of messages) {
try {
// 处理消息
const body = typeof message.body === 'string'
? JSON.parse(message.body)
: message.body;
results.push({
messageId: message.messageId,
body,
enqueuedTimeUtc: message.enqueuedTimeUtc,
});
// 完成消息处理
await receiver.completeMessage(message);
} catch (error) {
console.error('处理消息失败:', error);
// 将消息标记为死信
await receiver.deadLetterMessage(message, {
deadLetterReason: 'ProcessingError',
deadLetterErrorDescription: error.message,
});
}
}
return results;
} catch (error) {
throw new Error(`接收消息失败: ${error.message}`);
} finally {
await receiver.close();
}
}
// 消息处理器
async processQueueMessages(queueName, messageHandler) {
const receiver = this.client.createReceiver(queueName);
receiver.subscribe({
processMessage: async (message) => {
try {
const body = typeof message.body === 'string'
? JSON.parse(message.body)
: message.body;
await messageHandler(body, message);
await receiver.completeMessage(message);
} catch (error) {
console.error('处理消息失败:', error);
await receiver.deadLetterMessage(message, {
deadLetterReason: 'ProcessingError',
deadLetterErrorDescription: error.message,
});
}
},
processError: async (args) => {
console.error('Service Bus错误:', args.error);
},
});
return receiver;
}
}
// 使用示例
const serviceBusService = new ServiceBusService();
// 发送消息
app.post('/send-message', async (req, res) => {
try {
await serviceBusService.sendToQueue('processing-queue', {
body: {
taskType: 'process-order',
orderId: req.body.orderId,
userId: req.body.userId,
},
applicationProperties: {
priority: req.body.priority || 'normal',
source: 'api',
},
});
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 消息处理器
serviceBusService.processQueueMessages('processing-queue', async (message, rawMessage) => {
console.log('处理消息:', message);
switch (message.taskType) {
case 'process-order':
await processOrder(message.orderId);
break;
case 'send-email':
await sendEmail(message.recipient, message.content);
break;
default:
console.warn('未知任务类型:', message.taskType);
}
});
2. 主题和订阅
javascript
class ServiceBusTopicService extends ServiceBusService {
// 发送到主题
async sendToTopic(topicName, message) {
const sender = this.client.createSender(topicName);
try {
await sender.sendMessages([message]);
return { success: true };
} finally {
await sender.close();
}
}
// 订阅主题消息
async subscribeToTopic(topicName, subscriptionName, messageHandler) {
const receiver = this.client.createReceiver(topicName, subscriptionName);
receiver.subscribe({
processMessage: async (message) => {
try {
const body = typeof message.body === 'string'
? JSON.parse(message.body)
: message.body;
await messageHandler(body, message);
await receiver.completeMessage(message);
} catch (error) {
console.error('处理主题消息失败:', error);
await receiver.deadLetterMessage(message);
}
},
processError: async (args) => {
console.error('主题订阅错误:', args.error);
},
});
return receiver;
}
}
// 使用示例
const topicService = new ServiceBusTopicService();
// 发布事件
await topicService.sendToTopic('user-events', {
body: {
eventType: 'user-registered',
userId: '12345',
email: 'user@example.com',
timestamp: new Date().toISOString(),
},
applicationProperties: {
eventType: 'user-registered',
},
});
// 订阅事件
topicService.subscribeToTopic('user-events', 'email-service', async (message) => {
if (message.eventType === 'user-registered') {
await sendWelcomeEmail(message.email);
}
});
🧠 Cognitive Services AI服务
1. 文本分析
javascript
const { TextAnalyticsClient } = require('@azure/cognitiveservices-textanalytics');
class TextAnalyticsService {
constructor() {
this.client = new TextAnalyticsClient(
process.env.TEXT_ANALYTICS_ENDPOINT,
new DefaultAzureCredential()
);
}
// 情感分析
async analyzeSentiment(documents) {
try {
const results = await this.client.analyzeSentiment(documents);
return results.map(result => ({
id: result.id,
sentiment: result.sentiment,
confidence: result.confidenceScores,
sentences: result.sentences?.map(sentence => ({
text: sentence.text,
sentiment: sentence.sentiment,
confidence: sentence.confidenceScores,
})),
}));
} catch (error) {
throw new Error(`情感分析失败: ${error.message}`);
}
}
// 关键词提取
async extractKeyPhrases(documents) {
try {
const results = await this.client.extractKeyPhrases(documents);
return results.map(result => ({
id: result.id,
keyPhrases: result.keyPhrases,
}));
} catch (error) {
throw new Error(`关键词提取失败: ${error.message}`);
}
}
// 实体识别
async recognizeEntities(documents) {
try {
const results = await this.client.recognizeEntities(documents);
return results.map(result => ({
id: result.id,
entities: result.entities?.map(entity => ({
text: entity.text,
category: entity.category,
confidence: entity.confidenceScore,
offset: entity.offset,
length: entity.length,
})),
}));
} catch (error) {
throw new Error(`实体识别失败: ${error.message}`);
}
}
// 语言检测
async detectLanguage(documents) {
try {
const results = await this.client.detectLanguage(documents);
return results.map(result => ({
id: result.id,
primaryLanguage: result.primaryLanguage,
}));
} catch (error) {
throw new Error(`语言检测失败: ${error.message}`);
}
}
}
// 使用示例
const textAnalytics = new TextAnalyticsService();
app.post('/analyze-text', async (req, res) => {
try {
const documents = [
{ id: '1', text: req.body.text, language: 'zh' }
];
const [sentiment, keyPhrases, entities] = await Promise.all([
textAnalytics.analyzeSentiment(documents),
textAnalytics.extractKeyPhrases(documents),
textAnalytics.recognizeEntities(documents),
]);
res.json({
sentiment: sentiment[0],
keyPhrases: keyPhrases[0],
entities: entities[0],
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
2. OpenAI 集成
javascript
const { OpenAIClient } = require('@azure/openai');
class AzureOpenAIService {
constructor() {
this.client = new OpenAIClient(
process.env.AZURE_OPENAI_ENDPOINT,
new DefaultAzureCredential()
);
this.deploymentName = process.env.AZURE_OPENAI_DEPLOYMENT_NAME;
}
// 文本生成
async generateText(prompt, options = {}) {
try {
const response = await this.client.getCompletions(this.deploymentName, {
prompt: [prompt],
maxTokens: options.maxTokens || 100,
temperature: options.temperature || 0.7,
topP: options.topP || 1,
frequencyPenalty: options.frequencyPenalty || 0,
presencePenalty: options.presencePenalty || 0,
});
return {
text: response.choices[0]?.text?.trim(),
finishReason: response.choices[0]?.finishReason,
usage: response.usage,
};
} catch (error) {
throw new Error(`文本生成失败: ${error.message}`);
}
}
// 聊天对话
async chatCompletion(messages, options = {}) {
try {
const response = await this.client.getChatCompletions(this.deploymentName, {
messages,
maxTokens: options.maxTokens || 150,
temperature: options.temperature || 0.7,
});
return {
message: response.choices[0]?.message,
finishReason: response.choices[0]?.finishReason,
usage: response.usage,
};
} catch (error) {
throw new Error(`聊天对话失败: ${error.message}`);
}
}
// 文本嵌入
async getEmbeddings(texts) {
try {
const response = await this.client.getEmbeddings(
process.env.AZURE_OPENAI_EMBEDDING_DEPLOYMENT,
texts
);
return response.data.map(item => ({
index: item.index,
embedding: item.embedding,
}));
} catch (error) {
throw new Error(`获取嵌入失败: ${error.message}`);
}
}
}
// 使用示例
const openaiService = new AzureOpenAIService();
app.post('/chat', async (req, res) => {
try {
const messages = [
{ role: 'system', content: '你是一个有帮助的AI助手。' },
{ role: 'user', content: req.body.message }
];
const response = await openaiService.chatCompletion(messages);
res.json({ reply: response.message.content });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
📊 Application Insights 监控
1. 应用监控
javascript
const appInsights = require('applicationinsights');
class ApplicationInsightsService {
constructor() {
appInsights.setup(process.env.APPLICATIONINSIGHTS_CONNECTION_STRING)
.setAutoDependencyCorrelation(true)
.setAutoCollectRequests(true)
.setAutoCollectPerformance(true, true)
.setAutoCollectExceptions(true)
.setAutoCollectDependencies(true)
.setAutoCollectConsole(true)
.setUseDiskRetryCaching(true)
.start();
this.client = appInsights.defaultClient;
}
// 记录自定义事件
trackEvent(name, properties = {}, measurements = {}) {
this.client.trackEvent({
name,
properties,
measurements,
});
}
// 记录指标
trackMetric(name, value, properties = {}) {
this.client.trackMetric({
name,
value,
properties,
});
}
// 记录异常
trackException(exception, properties = {}) {
this.client.trackException({
exception,
properties,
});
}
// 记录依赖调用
trackDependency(dependencyTypeName, name, data, duration, success, properties = {}) {
this.client.trackDependency({
dependencyTypeName,
name,
data,
duration,
success,
properties,
});
}
// 记录请求
trackRequest(name, url, duration, responseCode, success, properties = {}) {
this.client.trackRequest({
name,
url,
duration,
responseCode,
success,
properties,
});
}
}
// 使用示例
const insights = new ApplicationInsightsService();
// Express中间件
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
insights.trackRequest(
`${req.method} ${req.path}`,
req.url,
duration,
res.statusCode,
res.statusCode < 400,
{
userAgent: req.get('User-Agent'),
userId: req.user?.id,
}
);
});
next();
});
// 业务事件追踪
app.post('/orders', async (req, res) => {
try {
const order = await createOrder(req.body);
insights.trackEvent('OrderCreated', {
orderId: order.id,
userId: req.user.id,
amount: order.total.toString(),
}, {
orderValue: order.total,
});
res.json(order);
} catch (error) {
insights.trackException(error, {
operation: 'createOrder',
userId: req.user?.id,
});
res.status(500).json({ error: error.message });
}
});
🔐 Key Vault 密钥管理
1. 密钥和机密管理
javascript
const { SecretClient } = require('@azure/keyvault-secrets');
const { DefaultAzureCredential } = require('@azure/identity');
class KeyVaultService {
constructor() {
const vaultUrl = `https://${process.env.KEY_VAULT_NAME}.vault.azure.net/`;
this.client = new SecretClient(vaultUrl, new DefaultAzureCredential());
}
// 获取密钥
async getSecret(secretName) {
try {
const secret = await this.client.getSecret(secretName);
return secret.value;
} catch (error) {
throw new Error(`获取密钥失败: ${error.message}`);
}
}
// 设置密钥
async setSecret(secretName, secretValue, options = {}) {
try {
const secret = await this.client.setSecret(secretName, secretValue, {
expiresOn: options.expiresOn,
notBefore: options.notBefore,
enabled: options.enabled !== false,
tags: options.tags,
});
return {
name: secret.name,
version: secret.properties.version,
createdOn: secret.properties.createdOn,
};
} catch (error) {
throw new Error(`设置密钥失败: ${error.message}`);
}
}
// 删除密钥
async deleteSecret(secretName) {
try {
const deletePoller = await this.client.beginDeleteSecret(secretName);
await deletePoller.pollUntilDone();
return { success: true };
} catch (error) {
throw new Error(`删除密钥失败: ${error.message}`);
}
}
// 列出密钥
async listSecrets() {
try {
const secrets = [];
for await (const secretProperties of this.client.listPropertiesOfSecrets()) {
secrets.push({
name: secretProperties.name,
version: secretProperties.version,
enabled: secretProperties.enabled,
createdOn: secretProperties.createdOn,
updatedOn: secretProperties.updatedOn,
});
}
return secrets;
} catch (error) {
throw new Error(`列出密钥失败: ${error.message}`);
}
}
}
// 配置管理器
class ConfigManager {
constructor() {
this.keyVault = new KeyVaultService();
this.cache = new Map();
this.cacheTimeout = 5 * 60 * 1000; // 5分钟缓存
}
async getConfig(key) {
const cacheKey = `config:${key}`;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.value;
}
try {
const value = await this.keyVault.getSecret(key);
this.cache.set(cacheKey, {
value,
timestamp: Date.now(),
});
return value;
} catch (error) {
// 如果Key Vault不可用,返回环境变量
return process.env[key];
}
}
}
// 使用示例
const configManager = new ConfigManager();
// 在应用启动时获取配置
async function initializeApp() {
try {
const dbConnectionString = await configManager.getConfig('DATABASE_CONNECTION_STRING');
const jwtSecret = await configManager.getConfig('JWT_SECRET');
const apiKey = await configManager.getConfig('THIRD_PARTY_API_KEY');
// 使用配置初始化服务
console.log('配置加载成功');
} catch (error) {
console.error('配置加载失败:', error);
process.exit(1);
}
}
initializeApp();
🚀 实际应用示例
完整的Azure集成应用
javascript
const express = require('express');
const multer = require('multer');
class AzureIntegratedService {
constructor() {
this.blobService = new AzureBlobService();
this.cosmosService = new CosmosDBService();
this.serviceBusService = new ServiceBusService();
this.textAnalytics = new TextAnalyticsService();
this.insights = new ApplicationInsightsService();
this.configManager = new ConfigManager();
}
async processFileUpload(file, userId, metadata = {}) {
const fileId = require('uuid').v4();
const fileName = `${userId}/${fileId}-${file.originalname}`;
try {
// 1. 上传到Blob Storage
const uploadResult = await this.blobService.uploadFile(fileName, file.buffer, {
contentType: file.mimetype,
metadata: { ...metadata, uploadedBy: userId },
});
// 2. 记录到Cosmos DB
const document = await this.cosmosService.createDocument({
id: fileId,
userId,
fileName: file.originalname,
fileSize: file.size,
mimeType: file.mimetype,
blobName: fileName,
status: 'uploaded',
partitionKey: userId,
});
// 3. 发送处理消息
await this.serviceBusService.sendToQueue('file-processing', {
body: {
fileId,
blobName: fileName,
mimeType: file.mimetype,
userId,
},
applicationProperties: {
fileType: file.mimetype,
},
});
// 4. 记录事件
this.insights.trackEvent('FileUploaded', {
fileId,
userId,
fileSize: file.size.toString(),
mimeType: file.mimetype,
});
return {
fileId,
status: 'uploaded',
url: uploadResult.url,
};
} catch (error) {
this.insights.trackException(error, {
operation: 'fileUpload',
userId,
});
throw error;
}
}
async analyzeText(text, userId) {
try {
const documents = [{ id: '1', text, language: 'zh' }];
const [sentiment, keyPhrases, entities] = await Promise.all([
this.textAnalytics.analyzeSentiment(documents),
this.textAnalytics.extractKeyPhrases(documents),
this.textAnalytics.recognizeEntities(documents),
]);
const analysisResult = {
sentiment: sentiment[0],
keyPhrases: keyPhrases[0],
entities: entities[0],
analyzedAt: new Date().toISOString(),
};
// 保存分析结果
await this.cosmosService.createDocument({
id: require('uuid').v4(),
userId,
type: 'text-analysis',
originalText: text,
analysis: analysisResult,
partitionKey: userId,
});
return analysisResult;
} catch (error) {
this.insights.trackException(error, {
operation: 'textAnalysis',
userId,
});
throw error;
}
}
}
// Express应用
const app = express();
const upload = multer({ storage: multer.memoryStorage() });
const azureService = new AzureIntegratedService();
app.use(express.json());
// 文件上传
app.post('/upload', upload.single('file'), async (req, res) => {
try {
const result = await azureService.processFileUpload(
req.file,
req.user.id,
{ source: 'web-upload' }
);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 文本分析
app.post('/analyze-text', async (req, res) => {
try {
const result = await azureService.analyzeText(req.body.text, req.user.id);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 获取用户文件
app.get('/files', async (req, res) => {
try {
const files = await azureService.cosmosService.queryDocuments({
query: 'SELECT * FROM c WHERE c.userId = @userId AND c.type != @excludeType',
parameters: [
{ name: '@userId', value: req.user.id },
{ name: '@excludeType', value: 'text-analysis' }
],
});
res.json(files);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000, () => {
console.log('Azure集成应用启动在端口 3000');
});
📚 最佳实践总结
- 身份验证:使用DefaultAzureCredential进行统一身份验证
- 错误处理:实现重试机制和优雅降级
- 监控:使用Application Insights进行全面监控
- 配置管理:使用Key Vault管理敏感配置
- 资源管理:正确关闭客户端连接和资源
- 性能优化:使用连接池和批量操作
- 安全性:遵循最小权限原则配置RBAC
通过掌握这些Azure服务集成技术,您将能够构建强大、可扩展的云原生Node.js应用程序。