预测:多云

进入您的 Windows 混合 Node.js 天蓝色的解决方案

Joseph Fultz

 

Joseph FultzNode.js 已被很多的记者到很晚,和高度被吹捧为其异步 I/O 模型,释放做其他工作,同时等待 I/O 响应的主线程。Node.js 的首要规则是 I/O 的开销,它会尝试通过迫使异步 I/O 模型减少开支。我一直在思考如何可能会被纳入现有的框架。如果你从零开始,是相对容易的技术选择的布局和作出的决定,即使决定很大程度基于酷因子孤独。但是,如果目标是要在一个解决方案中的一部分执行技术更新,诀窍采摘是当前、 有未来、 不会有很多额外的成本和与现有的解决方案景观合身的东西。

这正是要在此列中显示。我会带一个现有的解决方案,它允许查看的文档中存储,但需要一个共享的访问签名下载它们。这套解决方案将会添加一个简单的用户界面,使用 Node.js。为了帮助执行,我会利用一些常用的框架为 Node.js。该解决方案,因此,将包括:

  • Node.js—the 核心引擎
  • 表达 — — 模型-视图-控制器 (MVC) 的样式框架
  • 玉 — — 一个渲染和模板化引擎

在一起这三个工具将提供丰富的框架,从它生成用户界面,就像使用 ASP.NET MVC 3 和剃刀一样。

Visual J# 入门

如果你是新到 Node.js,也许最好开始与从微软公司在可用的预排 windowsazure.com/develop/nodejs。您还需要安装的 Windows Azure Node.js SDK。此外,您可能需要花一点时间闲逛快递 (expressjs.com)、 玉器 (玉 lang.com)。如果你是新的这些工具,你会发现一些熟悉的概念和熟悉又陌生的语法混合使用。

对于这种情况下,我现有的服务将会做这项工作在 Windows Azure 方面,与 Windows Azure 主办基于 Node.js 的网站将会调用这些服务要呈现的访问文档的列表。一般情况下,它是间接的有用的做法,放在客户端和后端服务之间层。这株的服务接口的任何更改,但真正的价值往往是在额外功能的灵活性和的方式,您可以包括和排除后端服务提供商。

在现有解决方案中,作为代表图 1,目的是给用户的访问权限,只是如果他被验证,这是生成共享访问签名 (SAS)。这个想法是授予读访问权限进行身份验证的那些然后再后来授予完全创建、 读取、 更新、 删除 (CRUD) 访问特定文档基于角色和成员资格级别。在这里我会只专注的读取权限。

The Request Sequence
图 1 请求序列

创建服务

将模拟验证服务返回一个 id。后续服务呼叫将检索的文件的列表。我使用的 ("文档") 的 Windows Azure 存储容器具有受限制的公共权限。我想,即使用户没有通过身份验证,但我不想未经身份验证的用户能够打开的文件提供的文档的列表。我已经创建了 api 的两个调用签名如下:

http://[host]/admin/GetAccess?user=[user] & pwd = [密码]
 http://[host]/admin/files?accessId=[authId

当然,你会更切合实际的身份验证服务,并不使用查询字符串,并不会使用 SSL ; 我将不会覆盖那片这里的解决方案。

第一,我需要一种方法来创建 SAS (请参见图 2)。 我需要这种方法创建的生成文档列表中的方法时,不久。

图 2 用于获取的共享的访问,签名的方法

public string GetSharedAccessSignature()
{
  string sas = "";          
  sas = (string) System.Web.HttpContext.Current.Cache.Get("sas");
  // If no SAS then get one
  if (sas == null)
  {
    // TODO: hardcoded container, move to config
    CloudBlobContainer container = 
      blobClient.GetContainerReference("documents");
    // Ask the container for SAS passing in the a newly initialized policy
    sas = container.GetSharedAccessSignature(new SharedAccessPolicy()
    {
      SharedAccessStartTime = DateTime.Now,
      SharedAccessExpiryTime = DateTime.Now.AddMinutes(MaxMinutes),
      Permissions = 
        SharedAccessPermissions.Read | SharedAccessPermissions.List
    });
    // Add to cache for reuse because this isn't a per-user SAS
    System.Web.HttpContext.Current.Cache.Add("sas", sas, null,
      DateTime.Now.AddMinutes(MaxMinutes), new TimeSpan(0,0,5,0,0),
      CacheItemPriority.High, null);
  }
  return sas
}

在最大程度上,这是相当典型的 Windows Azure 存储代码直到对 GetSharedAccessSignature 的调用。 没有一个共享的访问策略在这里,所以我需要传递关于何时开始或停止允许访问和权限的类型信息。 所有我想要提供通过 SAS 是读取和列出文件的能力。 此外,SAS 理论上将使用的任何人进行身份验证,因为我它向缓存中添加重用避免碰撞,减少客户流失中生成的访问键。

服务接口将被配置为 WebMethod:

[OperationContract]
[WebGet(UriTemplate = "Files?accessId={accessId}")]
List<BlobInfo> GetFiles(string accessId);

请注意,使用 BlobInfo 的自定义类 — — 同样的我使用的间接寻址。 我想要返回的特定字段和 IListBlobItem 并不一定代表他们。 所以,我就会封成我喜欢的类型的列表从 IListBlobItems 返回的信息中所示图 3

图 3 GetFiles 执行

public List<BlobInfo> GetFiles(string accessId)
{
  List<BlobInfo> blobs = new List<BlobInfo>();
  CloudBlobClient sasBlobClient = default(CloudBlobClient);
  CloudStorageAccount storageAccount =
    CloudStorageAccount.FromConfigurationSetting(
    "StorageAccountConnectionString");
  string sas = default(string);
  if(accessId.Length > 0)
  {
    // For the mock just make a simple check
    if(VerifyId(accessId))
    {
      sas = GetSharedAccessSignature();
      // Create the blob client directly, using the SAS
      sasBlobClient = new CloudBlobClient(storageAccount.BlobEndpoint,
        new StorageCredentialsSharedAccessSignature(sas));
    }
  }
  else
  {
    sasBlobClient = storageAccount.CreateCloudBlobClient();
  }
  CloudBlobContainer blobContainer =
    sasBlobClient.GetContainerReference("documents");
  foreach (IListBlobItem blob in blobContainer.ListBlobs())
  {
    BlobInfo info = new BlobInfo();
    info.Name = blob.Uri.LocalPath;
    info.Uri = blob.Uri.AbsoluteUri;
    info.Sas = sas;
    info.CombinedUri = blob.Uri.AbsoluteUri + sas;
    blobs.Add(info);
  }
  return blobs;
}

值得注意的是在图 3 我使用 SAS 如果对用户进行验证,返回一个列表,尊重在容器上的访问策略。

在地方的代表性状态传输 (REST) 服务可以通过浏览器窗口运行快速测试。 通过这种方式设置服务接口,变得容易,我通过使用一个知名的值,直到我有模拟验证 for 循环生成列表和 SAS 正常运行。 一旦完成,VerifyId(string) 仅检查以查看是否缓存,并将 accessId 的关键等于一个凭据。 图 4 显示不经过身份验证的情况下返回的列表。 因为服务返回的列表并不通过身份验证,SAS 值设置为零。 因此,我可以使用数据呈现列表中,但我不能给一个工作链接给用户,因为有没有 SAS。

An Unauthenticated List
图 4 未经身份验证的列表

图 5 显示的经过身份验证的列表,并包括 SAS。

An Authenticated List with the SAS
图 5 SAS 已通过身份验证的列表

它将 Node.js 客户端通过服务从经过身份验证的调用将返回排序的工作并与 uri postfixed 的 SAS 呈现超链接。 为了帮助的我已经在这样,客户端需要访问只有一个元素提供 CombinedUri 元。 最后,虽然 XML 是伟大的因为我在 Node.js 工作,很有意义改变的归因要返回 JSON,这样的服务响应可以直接消耗作为对象的接口:

[WebGet(UriTemplate = "Files?accessId={accessId}",
  ResponseFormat=WebMessageFormat.Json)]

这里是什么 JSON 输出看起来就像:

[{"CombinedUri":"https:\/\/footlocker.blob.core.windows.
net\/documents\/AzureKitchen-onesheet.docx?st=2012-03-05T05%3A22%3A22Z&se=2012-03-05T05%3A27%3A22Z&sr=c&sp=rl&sig=Fh41ZuV2y2z5ZPHi9OIyGMfFK%2F4zudLU0x5bg25iJas%3D","Name":"\/documents\/AzureKitchen-onesheet.docx","Sas":"?st=2012-03-05T05%3A22%3A22Z&se=2012-03-05T05%3A27%3A22Z&sr=c&sp=rl&sig=Fh41ZuV2y2z5ZPHi9OIyGMfFK%2F4zudLU0x5bg25iJas%3D","Uri":"https:\/\/footlocker.blob.core.windows.
net\/documents\/AzureKitchen-onesheet.docx"}]

如上所述,JSON 是我们最终想在这里,因为它是快递和玉内直接消耗的。

Node.js UI

我已设置了 Node.js、 快递和玉,所以我准备好创建用户界面。 我已经经历了起床 Node.js 角色的部署和在 Visual Studio 中运行的进程,但这是一个相当详细和完全手动的过程。 所以,因为有了这样的 Node.js 部分没有工具集成,我会用崇高的文本 2 来做我的编辑和铬调试 (门将 Janczuk 博客上所述 bit.ly/uvufEM)。

我应该提及几个内务管理项目。 对于新手来说,我用人的框架提供了某些功能,MVC 和模板渲染引擎周围一些易于使用包装:

  • (想简化的 WebClient) 的简单休息电话 Restler
  • 表示一般的 MVC 样式应用程序框架
  • 模板渲染,类似于使用 ASP.NET MVC 中的剃刀引擎玉

这些都是在 Node.js (如.net 中的 Dll) 中的所有考虑的模块,通常从 GitHub 通过节点软件包管理器 (故宫) 安装。 例如,若要安装 Restler,使用命令"故宫安装 restler"从在项目文件夹内。 这需要手动安装的模块,并在项目中添加对它的引用的地方。

最后一位的陌生的信息。 你会发现很多嵌套在其他函数中的匿名函数。 我最好的建议是,只是重新格式化代码足够看到嵌套,因为您使用它直到您自然解析它而无需重新设置它的格式。 我会尝试巢我以提高可读性的样本,以及使用从崇高,很好地彩色,有助于与可读性的屏幕截图。

我使用过的命令新 AzureService 和新 AzureWeb­创建一个名为 AzureNodeExpress 的应用程序的角色。 我也做了几个其他修改。 在 server.js 中添加路由到索引页 ; 模拟 ASP.NET 是 MVC 项目中使用的 MapRoutes 方法。

Server.js 修改

很像在 C# 中使用的语句,我需要告诉我将利用哪些库的 Node.js。 在 Node.js,我就会通过为变量赋值的返回值来设置这些引用要求 ('[lib 名称]') 函数。 一旦设置的引用,则我做一点配置设置的部分引擎变量 (例如,将设置"查看发动机"为"玉")。 特别感兴趣的是"视图引擎"路由器、 bodyParser、 cookieParser 和会话。

我跳过一些更多的世俗的元素,但我想我的路由设置。 为获取谓词索引页上我会简单地呈现视图直接:

app.get('/index',
  function(req, res){
    res.render('index.jade', {title: 'index'});
  }
);

然而,为邮政的谓词我想要的指数模型经过处理。 要实现这一目标有以"绑定"的模型定义的方法:

app.post('/index', index.GetAccessKey.bind(index));

在地方的路由需要设置视图和模型。

View—Index.jade

在某种意义上,我我跳绳从开头到结尾到视图中,从控制器走,但在 MVC 样式中工作时,我想创建一个简化的视图,以针对第一次工作。 玉语法基本上是没有方括号内的装饰的 HTML。 我整个的玉模板所示图 6

图 6 玉模板

html
head
  title Default
body
  h1 File List Home Page
  br
  label Welcome #{username}
  form(method='post', action='/index')
    label Username:
      input(name='username', type='text')
    br
    label Password:
      input(name='password', type='password')
    br
    button(type='submit') Login
  h2 Files   
  form
    table(border="1")
      tr
        td Name
        td Uri
        each doc in docList
          tr
            td #{doc.Name}
            td
              a(href=#{doc.CombinedUri}) #{doc.Name}

请注意这里是 # {[var]} 来引用变量和表模板与在循环中,这是一种缩写 foreach 的使用。 我已经任意命名想要遍历文档列表的项目的列表。 这是重要的因为在 index.js 页面中请问玉来呈现这种观点,我需要在值中传递的文档列表。 事情是非常基本在这里,因为我只我创建用户界面开发人员 — — 朴素的。

Model—Index.js

具有设置于运行库的基础设施,server.js 和 index.jade 中的最后视图模板,我感觉与执行,这发生在 index.js 中的肉。 请记住我设置为应用程序的绑定。投递到索引页。 绑定将加载并运行原型已经创建的 index.js。 要做到这一点,我会向中添加函数索引原型中,如中所示图 7。 实质上,我是创建一个命名的函数 (例如,GetAccessKey),作为其执行机构定义匿名函数。 在每个函数中我将使用 Restler 模块简化需要做出的其余部分调用。

图 7 Index.js 函数

第一个调用绑定发生的后一旦到 GetAccessKey,只是采用的用户名和密码提交通过窗体发布,将其追加到该 URI 作为查询字符串的一部分,并使用 Restler 来执行 Get 操作。 请记住,在 Node.js 的所有通信都发生了以异步方式,这是你会看到的高度嵌套的匿名函数扩散的原因之一。 我在忠实于这种模式对 rest.get 的调用中,定义请求完成后执行的匿名函数。 没有错误处理代码,在行被简化为:

rest.get (uri).on('complete',
  function(result){
    accesskey = result;
this.ShowDocs (req, res);}
  )

我们希望重新格式化将有助于提供更好的理解正在进行。 一旦从我的服务已经关键,我将后缀它到方法中的 URI,要读取文档列表。 现在事情从通常会稍有不同。 在匿名函数中处理其他调用以获取文档列表的回报,我问玉呈现结果对我来说:

res.render ('index', {title: "Doc List",
    layout: false,
    docList: result,
    username: req.BODY.username});

我前面提到的在模板中创建的变量名称"文档列表"。现在,我需要确保我使用的正确的名称。 对 res.render 的调用告诉快递框架要呈现的"指数"资源,然后将参数传递通过冒号和逗号分隔名称: 值对的列表。

运行时

如果我尝试通过浏览找到要下载的文件之一,什么也不给我。 找不到该 Web 页。 你可能期望从 Windows Azure 存储,未经授权的错误,但如果您尝试访问标记为私人性质的东西,什么返回是该资源不存在。 这是由设计,和它是可取的因为这是"私人"的东西不应该存在向公众,甚至在概念。 如果 401 错误,而是返回,它将表明什么是真的存在的违反安全策略由私人代表。

因为我已经安全的存储位置,允许没有直接访问。 然而,一旦我运行示例代码,这个故事是稍有不同。 我发布应用程序使用 Windows PowerShell 发布-AzureService 命令,浏览到该页面,输入我的凭据 ; 再给我拿到文件的链接的列表 (请参见图 8)。

Links to the Files
图 8 到文件的链接

我的服务中间商对存储的调用,因为我是能够列出的文件,即使我不能直接将其列出。 此外,因为每个链接 postfixed sas,当我点击它我我提示打开或保存的目标文档。

接近尾声了

如果你感兴趣的新的或趋势的技术作为一种方式进化的应用程序的 Windows Azure,你是一个真正的信徒在 Node.js 域中发生了什么,Windows Azure 已经满足您的要求 — — 不只与主机托管解决方案,但也带有选项 (例如客户端库的 Node.js 在发展方面,击中其它 API 直接或间接通过示在这里。 发展肯定会很多更好、 更方便地如果 Node.js 已经适当工具的支持,并相信我们最终会看到某种形式的与 Visual Studio 集成,如果 Node.js 的流行继续增长。

Joseph Fultz 是 Hewlett-Packard Co. 的软件架构师,参与 HP.com 全球 IT 小组的工作。他以前是微软,使用其顶级企业和 ISV 客户定义的体系结构和设计解决方案的软件设计师。

由于下面的技术专家,检讨这篇文章:Bruno Terkaly