如何使用适用于 Azure 移动应用的 Node.js SDK
本文提供了详细信息和示例,介绍如何使用适用于 Azure 移动应用的 NodeJS 后端。
介绍
使用 Azure 移动应用可将移动优化的数据访问 Web API 添加到 Web 应用程序。 Azure 移动应用 SDK 适用于 ASP.NET Framework 和 Node.js Web 应用程序。 此 SDK 提供以下操作:
- 数据访问的表操作(读取、插入、更新、删除)
- 自定义 API 操作
这两种操作都可用于 Azure 应用服务允许的所有标识提供者之间的身份验证。 这些提供程序包括 Facebook、Twitter、Google 和 Microsoft 等社交标识提供者,以及企业标识的 Microsoft Entra ID。
支持的平台
Azure 移动应用 Node.js SDK 支持 Node 6.x 及更高版本,已通过测试的最高版本为 Node 12.x。 其他 Node 版本可能有效,但不受支持。
Azure 移动应用 Node.js SDK 支持两个数据库驱动程序:
- node-mssqll 驱动程序支持 Azure SQL 数据库和本地 SQL Server 实例。
- sqlite3 驱动程序仅支持单个实例上的 SQLite 数据库。
使用命令行创建基本 Node 后端
每个 Azure 移动应用 Node.js 后端都以快速应用程序的形式启动。 在适用于 Node.js 的 Web 服务框架中,Express 最广为使用。 可按以下方式创建基本的 Express 应用程序:
在命令窗口或 PowerShell 窗口中,为项目创建目录:
$ mkdir basicapp
运行
npm init
初始化包结构:$ cd basicapp $ npm init
npm init
命令将提出一系列问题以初始化项目。 查看示例输出:从 npm 存储库安装
express
和azure-mobile-apps
库:npm install --save express azure-mobile-apps
创建
app.js
文件,实现基本移动服务器:var express = require('express'), azureMobileApps = require('azure-mobile-apps'); var app = express(), mobile = azureMobileApps(); // Define a TodoItem table. mobile.tables.add('TodoItem'); // Add the Mobile API so it is accessible as a Web API. app.use(mobile); // Start listening on HTTP. app.listen(process.env.PORT || 3000);
此应用程序创建具有单个终结点 (/tables/TodoItem
) 的移动优化 Web API,让用户使用动态架构访问基础 SQL 数据存储,而无需经过身份验证。 它适用于以下客户端库快速入门:
可以在 GitHub 上的示例区域中找到此基本应用程序的代码。
启用应用程序的主页
许多应用程序是 Web 和移动应用的组合。 可以使用 Express 框架组合两个分面。 但有时,我们可能只想要实现移动接口。 移动接口用于提供主页,确保应用服务已启动并在运行。 可以提供自己的主页,或启用临时主页。 若要启用临时主页,请使用以下代码来实例化 Azure 移动应用:
var mobile = azureMobileApps({ homePage: true });
如果想要让此选项仅在本地开发时可供使用,可以将此设置添加到 azureMobile.js
配置文件:
module.exports = {
homePage: true,
};
可以根据需要将其他设置添加到 azureMobile.js 文件。
表操作
azure-mobile-apps Node.js Server SDK 提供将存储在 Azure SQL 数据库中的表公开为 Web API 的机制。 它提供五个操作:
操作 | 说明 |
---|---|
GET /tables/tablename |
获取表中的所有记录。 |
GET /tables/tablename/:id |
获取表中的特定记录。 |
POST /tables/tablename |
在表中创建记录。 |
PATCH /tables/tablename/:id |
在表中更新记录。 |
DELETE /tables/tablename/:id |
删除表中的记录。 |
此 Web API 支持 OData v3,并扩展表架构以支持脱机数据同步。
使用动态架构定义表
表必须先经过定义才能使用。 可以使用静态架构来定义表(在架构中定义列),或者动态定义表(SDK 根据传入的请求控制架构)。 此外,可以通过将 JavaScript 代码添加到定义,来控制 Web API 的特定层面。
根据最佳做法,应在 tables
目录中的 JavaScript 文件内定义每个表,并使用 tables.import()
方法导入表。 扩展 basic-app 示例后,调整 app.js 文件:
var express = require('express'),
azureMobileApps = require('azure-mobile-apps');
var app = express(),
mobile = azureMobileApps();
// Define the database schema that is exposed.
mobile.tables.import('./tables');
// Provide initialization of any tables that are statically defined.
mobile.tables.initialize().then(function () {
// Add the Mobile API so it is accessible as a Web API.
app.use(mobile);
// Start listening on HTTP.
app.listen(process.env.PORT || 3000);
});
在 ./tables/TodoItem.js 中定义表:
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Additional configuration for the table goes here.
module.exports = table;
表默认使用动态架构。
使用静态架构定义表
可以将列显式定义为通过 Web API 公开。 azure-mobile-apps Node.js SDK 自动将脱机数据同步所需的任何其他列添加到所提供的列表。 例如,快速入门客户端应用程序需要包含两个列的表:text
(字符串)和 complete
(布尔值)。 可以在表定义 JavaScript 文件中(位于 tables
目录中)定义该表,如下所示:
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Define the columns within the table.
table.columns = {
"text": "string",
"complete": "boolean"
};
// Turn off the dynamic schema.
table.dynamicSchema = false;
module.exports = table;
如果以静态方式定义表,则还必须调用 tables.initialize()
方法,在启动时创建数据库架构。 tables.initialize()
方法返回 Promise,使 Web 服务不会在数据库初始化之前处理请求。
使用 SQL Server Express 作为本地计算机上的开发数据存储
Azure 移动应用 Node.js SDK 提供三种现成可用的数据服务选项:
- 使用内存驱动程序提供非持久性示例存储。
- 使用 mssql 驱动程序提供可供开发使用的 SQL Server Express 数据存储。
- 使用 mssql 驱动程序提供可供生产使用的 Azure SQL 数据库数据存储。
Azure 移动应用 Node.js SDK 利用 mssql Node.js 包来建立和使用 SQL Server Express 与 SQL 数据库的连接。 若要使用此包,需要在 SQL Server Express 实例上启用 TCP 连接。
提示
内存驱动程序不提供完整的测试工具集。 若要在本地测试后端,建议使用 SQL Server Express 数据存储和 mssql 驱动程序。
运行 Configuration Manager:
- 在树菜单中,展开“SQL Server 网络配置”节点。
- 选择“instance-name 的协议”。
- 右键单击“TCP/IP”,并选择“启用”。 在弹出对话框中选择“确定”。
- 在树菜单中,选择“SQL Server 服务”。
- 右键单击“SQL Server (instance-name)”,并选择“重启”。
- 关闭 Configuration Manager。
还需要创建 Azure 移动应用可用于连接到数据库的用户名和密码。 确保创建的用户具有 dbcreator
服务器角色。 如需详细了解如何配置用户,请参阅 SQL Server 文档
请务必记下选择的用户名和密码。 可能需要根据数据库要求分配其他服务器角色或权限。
Node.js 应用程序将读取 SQLCONNSTR_MS_TableConnectionString
环境变量,以读取此数据库的连接字符串。 可以在环境中设置此变量。 例如,可以使用 PowerShell 设置此环境变量:
$env:SQLCONNSTR_MS_TableConnectionString = "Server=127.0.0.1; Database=mytestdatabase; User Id=azuremobile; Password=T3stPa55word;"
通过 TCP/IP 连接访问数据库。 提供连接的用户名和密码。
配置项目以进行本地开发
Azure 移动应用从本地文件系统读取名为 azureMobile.js
的 JavaScript 文件。 不要使用此文件在生产环境中配置 Azure 移动应用 SDK。 请改用 Azure 门户中的“应用设置”。
azureMobile.js 文件应导出配置对象。 最常见的设置如下:
- 数据库设置
- 诊断日志记录设置
- 备用 CORS 设置
以下示例 azureMobile.js 文件实现上述数据库设置:
module.exports = {
cors: {
origins: [ 'localhost' ]
},
data: {
provider: 'mssql',
server: '127.0.0.1',
database: 'mytestdatabase',
user: 'azuremobile',
password: 'T3stPa55word'
},
logging: {
level: 'verbose'
}
};
建议将 azureMobile.js
添加到 .gitignore
文件(或其他源代码管理 ignore 文件),防止将密码存储在云中。
配置移动应用的应用设置
azureMobile.js
文件中的大多数设置在 Azure 门户中都有对等的应用设置。 使用以下列表在“应用设置”中配置应用:
应用设置 | azureMobile.js 设置 | 说明 | 有效值 |
---|---|---|---|
MS_MobileAppName | name | 应用的名称 | string |
MS_MobileLoggingLevel | logging.level | 要记录的消息的最小日志级别 | error、warning、info、verbose、debug、silly |
MS_DebugMode | 调试 | 启用或禁用调试模式 | true、false |
MS_TableSchema | data.schema | SQL 表的默认架构名称 | 字符串(默认值:dbo) |
MS_DynamicSchema | data.dynamicSchema | 启用或禁用调试模式 | true、false |
MS_DisableVersionHeader | 版本(设置为 undefined) | 禁用 X-ZUMO-Server-Version 标头 | true、false |
MS_SkipVersionCheck | skipversioncheck | 禁用客户端 API 版本检查 | true、false |
更改大多数应用设置后都需要重新启动服务。
使用 Azure SQL 作为生产数据存储
无论使用哪种 Azure 应用服务应用程序类型,将 Azure SQL 数据库用作数据存储的过程都是相同的。 如果还没有这样做,请按照以下步骤创建 Azure 移动服务后端。 创建 Azure SQL 实例,然后将应用设置 SQLCONNSTR_MS_TableConnectionString
设置为你想要使用的 Azure SQL 实例的连接字符串。 确保运行后端的 Azure 应用服务可以与 Azure SQL 实例通信。
要求在访问表时进行身份验证
若要对 tables
终结点使用应用服务身份验证,必须先在 Azure 门户中配置应用服务身份验证。 有关详细信息,请参阅要使用的标识提供者的配置指南:
每个表都有一个访问属性用于控制对表的访问。 以下示例显示了以静态方式定义的、要求身份验证的表。
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Define the columns within the table.
table.columns = {
"text": "string",
"complete": "boolean"
};
// Turn off the dynamic schema.
table.dynamicSchema = false;
// Require authentication to access the table.
table.access = 'authenticated';
module.exports = table;
访问属性可接受三个值中的一个:
- anonymous 表示允许客户端应用程序未经身份验证即可读取数据。
- authenticated 表示客户端应用程序必须随请求发送有效的身份验证令牌。
- disabled 表示此表当前已禁用。
如果未定义访问属性,则允许未经身份验证的访问。
对表使用身份验证声明
可以设置不同的声明,在设置身份验证时将请求这些声明。 这些声明通常无法通过 context.user
对象获取。 但是,可以使用 context.user.getIdentity()
方法来检索它们。 getIdentity()
方法返回可解析成某个对象的 Promise。 该对象由身份验证方法(facebook
、google
、twitter
、microsoftaccount
或 aad
)进行键控。
注意
如果通过 Microsoft Entra ID 使用 Microsoft 身份验证,则身份验证方法不是aad
microsoftaccount
。
例如,如果设置了 Microsoft Entra 身份验证并请求电子邮件地址声明,则可以使用下表控制器将电子邮件地址添加到记录:
var azureMobileApps = require('azure-mobile-apps');
// Create a new table definition.
var table = azureMobileApps.table();
table.columns = {
"emailAddress": "string",
"text": "string",
"complete": "boolean"
};
table.dynamicSchema = false;
table.access = 'authenticated';
/**
* Limit the context query to those records with the authenticated user email address
* @param {Context} context the operation context
* @returns {Promise} context execution Promise
*/
function queryContextForEmail(context) {
return context.user.getIdentity().then((data) => {
context.query.where({ emailAddress: data.aad.claims.emailaddress });
return context.execute();
});
}
/**
* Adds the email address from the claims to the context item - used for
* insert operations
* @param {Context} context the operation context
* @returns {Promise} context execution Promise
*/
function addEmailToContext(context) {
return context.user.getIdentity().then((data) => {
context.item.emailAddress = data.aad.claims.emailaddress;
return context.execute();
});
}
// Configure specific code when the client does a request.
// READ: only return records that belong to the authenticated user.
table.read(queryContextForEmail);
// CREATE: add or overwrite the userId based on the authenticated user.
table.insert(addEmailToContext);
// UPDATE: only allow updating of records that belong to the authenticated user.
table.update(queryContextForEmail);
// DELETE: only allow deletion of records that belong to the authenticated user.
table.delete(queryContextForEmail);
module.exports = table;
若要查看哪些声明可用,请使用 Web 浏览器查看站点的 /.auth/me
终结点。
禁用对特定表操作的访问
除了出现在表上以外,访问属性还可用于控制单个操作。 共有四项操作:
read
是对表运行的 RESTful GET 操作。insert
是对表运行的 RESTful POST 操作。update
是对表运行的 RESTful PATCH 操作。delete
是对表运行的 RESTful DELETE 操作。
例如,若要提供未经身份验证的只读表:
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Read-only table. Only allow READ operations.
table.read.access = 'anonymous';
table.insert.access = 'disabled';
table.update.access = 'disabled';
table.delete.access = 'disabled';
module.exports = table;
调整与表操作配合使用的查询
表操作的常见要求是提供受限制的数据视图。 例如,可以提供标有已经过身份验证的用户 ID 的表,以便只有你能够读取或更新自己的记录。 以下表定义提供此功能:
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Define a static schema for the table.
table.columns = {
"userId": "string",
"text": "string",
"complete": "boolean"
};
table.dynamicSchema = false;
// Require authentication for this table.
table.access = 'authenticated';
// Ensure that only records for the authenticated user are retrieved.
table.read(function (context) {
context.query.where({ userId: context.user.id });
return context.execute();
});
// When adding records, add or overwrite the userId with the authenticated user.
table.insert(function (context) {
context.item.userId = context.user.id;
return context.execute();
});
module.exports = table;
正常运行查询的操作包含一个可以使用 where
子句进行调整的查询属性。 该查询属性是一个 QueryJS 对象,用于将 OData 查询转换成数据后端可以处理的某种形式。 在简单的相等性比较方案中(如上例),可以使用映射。 还可以添加特定的 SQL 子句:
context.query.where('myfield eq ?', 'value');
在表中配置软删除
软删除并不实际删除记录。 它将已删除的列设置为 true,将记录标记为已在数据库中删除。 Azure 移动应用 SDK 自动从结果中删除已软删除的记录,除非移动客户端 SDK 使用 includeDeleted()
。 若要为表配置软删除,请在表定义文件中设置 softDelete
属性:
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Define the columns within the table.
table.columns = {
"text": "string",
"complete": "boolean"
};
// Turn off the dynamic schema.
table.dynamicSchema = false;
// Turn on soft delete.
table.softDelete = true;
// Require authentication to access the table.
table.access = 'authenticated';
module.exports = table;
建立记录永久删除机制,例如客户端应用程序、WebJob、Azure 函数或自定义 API。
在数据库中植入数据
创建新应用程序时,可能需要在表中植入数据。 可在表定义 JavaScript 文件中植入数据,如下所示:
var azureMobileApps = require('azure-mobile-apps');
var table = azureMobileApps.table();
// Define the columns within the table.
table.columns = {
"text": "string",
"complete": "boolean"
};
table.seed = [
{ text: 'Example 1', complete: false },
{ text: 'Example 2', complete: true }
];
// Turn off the dynamic schema.
table.dynamicSchema = false;
// Require authentication to access the table.
table.access = 'authenticated';
module.exports = table;
仅当表是由 Azure 移动应用 SDK 创建时,才能植入数据。 如果表已在数据库中,则不会在表中注入任何数据。 如果打开了动态架构,将从植入的数据推断架构。
建议显式调用 tables.initialize()
方法,在服务开始运行时创建表。
启用 Swagger 支持
Azure 移动应用随附内置的 Swagger 支持。 若要启用 Swagger 支持,请先安装 swagger-ui 作为依赖项:
npm install --save swagger-ui
然后,可以在 Azure 移动应用构造函数中启用 Swagger 支持:
var mobile = azureMobileApps({ swagger: true });
可能只想要在开发版本中启用 Swagger 支持。 可以使用 NODE_ENV
应用设置在开发中启用 Swagger 支持:
var mobile = azureMobileApps({ swagger: process.env.NODE_ENV !== 'production' });
swagger
终结点位于 http://你的站点.azurewebsites.net/swagger。 可以通过 /swagger/ui
终结点访问 Swagger UI。 如果选择要求在整个应用程序中进行身份验证,Swagger 将生成错误。 为获得最佳效果,请在“Azure 应用服务身份验证/授权”设置中选择允许未经身份验证的请求通过,并使用 table.access
属性控制身份验证。
如果希望只在本地进行开发时才使用 Swagger 支持,也可以将 Swagger 选项添加到 azureMobile.js
文件中。
自定义 API
除了通过 /tables
终结点的数据访问 API 以外,Azure 移动应用还可提供自定义 API 覆盖范围。 自定义 API 以类似于表定义的方法定义,可访问所有相同的功能,包括身份验证。
定义自定义 API
定义自定义 API 的方法与表 API 大致相同:
- 创建
api
目录。 - 在
api
目录中创建 API 定义 JavaScript 文件。 - 使用 import 方法导入
api
目录。
下面是根据前面使用的基本应用示例所做的原型 API 定义:
var express = require('express'),
azureMobileApps = require('azure-mobile-apps');
var app = express(),
mobile = azureMobileApps();
// Import the custom API.
mobile.api.import('./api');
// Add the Mobile API so it is accessible as a Web API.
app.use(mobile);
// Start listening on HTTP
app.listen(process.env.PORT || 3000);
让我们使用一个通过 Date.now()
方法返回服务器日期的示例 API。 以下是 api/date.js
文件:
var api = {
get: function (req, res, next) {
var date = { currentTime: Date.now() };
res.status(200).type('application/json').send(date);
});
};
module.exports = api;
每个参数是标准的 RESTful 谓词之一:GET、POST、PATCH 或 DELETE。 此方法是发送所需输出的标准 ExpressJS 中间件函数。
要求在访问自定义 API 时进行身份验证
Azure 移动应用 SDK 对 tables
终结点和自定义 API 都使用相同的方式实现身份验证。 若要在前一部分开发的 API 中添加身份验证,请添加 access
属性:
var api = {
get: function (req, res, next) {
var date = { currentTime: Date.now() };
res.status(200).type('application/json').send(date);
});
};
// All methods must be authenticated.
api.access = 'authenticated';
module.exports = api;
也可以指定对特定操作的身份验证:
var api = {
get: function (req, res, next) {
var date = { currentTime: Date.now() };
res.status(200).type('application/json').send(date);
}
};
// The GET methods must be authenticated.
api.get.access = 'authenticated';
module.exports = api;
对于要求身份验证的自定义 API,必须使用与 tables
终结点相同的令牌。
处理大型文件上传
Azure 移动应用 SDK 使用正文分析器中间件来接受和解码提交件的正文内容。 可以将正文分析器预先配置为接受大型文件上传:
var express = require('express'),
bodyParser = require('body-parser'),
azureMobileApps = require('azure-mobile-apps');
var app = express(),
mobile = azureMobileApps();
// Set up large body content handling.
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
// Import the custom API.
mobile.api.import('./api');
// Add the Mobile API so it is accessible as a Web API.
app.use(mobile);
// Start listening on HTTP.
app.listen(process.env.PORT || 3000);
该文件在传输之前是以 Base-64 编码的。 此编码会增加实际上传的大小(因此必须考虑该大小)。
执行自定义 SQL 语句
Azure 移动应用 SDK 还可以通过请求对象访问整个上下文。 可以轻松针对定义的数据提供程序执行参数化的 SQL 语句:
var api = {
get: function (request, response, next) {
// Check for parameters. If not there, pass on to a later API call.
if (typeof request.params.completed === 'undefined')
return next();
// Define the query. Anything that the mssql
// driver can handle is allowed.
var query = {
sql: 'UPDATE TodoItem SET complete=@completed',
parameters: [{
completed: request.params.completed
}]
};
// Execute the query. The context for Azure Mobile Apps is available through
// request.azureMobile. The data object contains the configured data provider.
request.azureMobile.data.execute(query)
.then(function (results) {
response.json(results);
});
}
};
api.get.access = 'authenticated';
module.exports = api;
调试
对 Azure 移动应用进行调试、诊断和故障排除
Azure 应用服务提供多种适用于 Node.js 应用程序的调试和故障排除方法。 若要入门针对 Node.js Azure 移动应用后端进行故障排除,请参阅以下文章:
Node.js 应用程序可访问各种诊断日志工具。 在内部,Azure 移动应用 Node.js SDK 使用 [Winston] 进行诊断日志记录。 启用调试模式,或者在 Azure 门户中将 MS_DebugMode
应用设置指定为 true,即可自动启用日志记录。 生成的日志显示在 Azure 门户上的诊断日志中。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈