离线下载
PDF版 ePub版

微软中文 · 更新于 2018-11-28 11:00:43

使用REST API访问Storage Service

本文是 Windows Azure 入门教学 的第七篇文章。

本文将会介绍如何使用REST API来直接访问 Storage Service。

在前三篇教学中,我们已经学习了使用 Windows Azure SDK所提供的 StorageClient来使用 Blob Storage, Queue Storage以及 Table Storage的基本方法。我们在前几篇教学中也提及最终 StorageClient也是通过发送 REST请求来与服务器端通信的。

在这篇教学中,我们会以 Blob Storage为例,说明如何使用 REST API直接与服务器进行通信。需要说明的是,这篇教学中使用的是 C#语言。但是由于 REST API实际上是通过 HTTP发送的 HTTP消息,使用其他语言的工程师同样可以参考代码逻辑了解如何构造 HTTP消息以便在其他编程语言中使用。

在开始本教学之前,请确保你从Windows Azure 平台下载下载并安装了最新的 Windows Azure开发工具。 本教学使用 Visual Studio 2010作为开发工具。

步骤一:准备工作

在本教学中我们将使用 List Blobs API,欲了解详细信息,请参见List Blobs

该 API的作用是返回给定的 Container中的 Blob信息。为了测试我们的代码我们首先需要有一个已经创建的 Container并且向其中添加至少一个 Blob。由于如何添加 Container和 Blob的方法我们已经在 Windows Azure入门教学系列 (四 ):使用 Blob Storage 中提过,在此不赘述。读者可以按照 Windows Azure入门教学系列 (四 ):使用 Blob Storage 中的代码创建名为 helloworldcontainer的 Container和名为 myfile的 Blob。 (只需注释掉删除 Blob的代码并运行程序即可 )

步骤二:创建解决方案和项目

首先,请确保 Storage Emulator已经启动。我们可以找到管理器的进程手动启动或者让 Visual Studio 2010帮助我们启动他。

右击工具栏中 Windows Azure模拟器的图标,选择” Show Storage Emulator UI”。弹出如下图所示的窗口:

我们要关注的是 Service management中 Blob所在的一行。要确保 Status为 Running。

确认完毕后启动 Visual Studio 2010,并且新建一个 Console项目。

步骤三:添加程序集引用

请在项目属性页里确认项目的 Target framework的值是 .NET Framework 4或 .NET Framework 3.5。然后在 Console项目中添加对 System.Web程序集的引用。该程序集安装在 GAC中。在 .NET标签下能够找到该程序集。我们将使用该程序集来发送 HTTP请求和接受 HTTP消息。

步骤四:添加代码

首先在项目中的 Program.cs中引用命名空间:

using   System.IO;

using   System.Collections.Specialized;

using   System.Collections;

using   System.Web;

using   System.Net;

然后在 Program.cs中添加如下代码 :

class   Program

{

     internal   class   CanonicalizedString

     {

         private   StringBuilder   canonicalizedString =  new   StringBuilder ();

         internal   CanonicalizedString(string   initialElement)

         {

             this .canonicalizedString.Append(initialElement);

         }

         internal   void   AppendCanonicalizedElement(string   element)

         {

             this .canonicalizedString.Append("/n" );

             this .canonicalizedString.Append(element);

         }

         internal   string   Value

         {

             get

             {

                 return   this .canonicalizedString.ToString();

             }

         }

     }

      const   string   bloburi =  @"http://127.0.0.1:10000/devstoreaccount1" ;

     const   string   accountname =  "devstoreaccount1" ;

     const   string   key =  "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" ;

     const   string   method =  "GET" ;

     static   void   Main(string [] args)

     {

         string   AccountName = accountname;

         string   AccountSharedKey = key;

         string   Address = bloburi;

         string   container =  "helloworldcontainer" ;

         //  创建请求字符串

         string   QueryString =  "?restype=container&comp=list" ;

         Uri   requesturi =  new   Uri (Address +  "/"   + container + QueryString);

         string   MessageSignature =  "" ;

         //   创建 HttpWebRequest 类

         HttpWebRequest   Request = (HttpWebRequest )HttpWebRequest .Create(requesturi.AbsoluteUri);

         Request.Method = method;

         Request.ContentLength = 0;

         Request.Headers.Add("x-ms-date" ,  DateTime .UtcNow.ToString("R" ));

         Request.Headers.Add("x-ms-version" ,  "2009-09-19" );

         //  开始创建签名

          MessageSignature +=  "GET/n" ;  //   Verb

         MessageSignature +=  "/n" ;  // Content-Encoding

         MessageSignature +=  "/n" ;  // Content-Language

         MessageSignature +=  "/n" ;  // Content-Length

         MessageSignature +=  "/n" ;  // Content-MD5

          MessageSignature +=  "/n" ;  // Content-Type

         MessageSignature +=  "/n" ;  // Date

         MessageSignature +=  "/n" ;  // If-Modified-Since

         MessageSignature +=  "/n" ;  // If-Match

         MessageSignature +=  "/n" ;  // If-None-Match

         MessageSignature +=  "/n" ;  // If-Unmodified-Since

         MessageSignature +=  "/n" ;  // Range

         // CanonicalizedHeaders

         ArrayList   list =  new   ArrayList ();

         foreach   (string   str  in   Request.Headers.Keys)

         {

             if   (str.ToLowerInvariant().StartsWith("x-ms-" ,  StringComparison .Ordinal))

             {

                 list.Add(str.ToLowerInvariant());

             }

         }

         list.Sort();

         foreach   (string   str2  in   list)

         {

             StringBuilder   builder =  new   StringBuilder (str2);

             string   str3 =  ":" ;

             foreach   (string   str4  in   GetHeaderValues(Request.Headers, str2))

             {

                 string   str5 = str4.Replace("/r/n" ,  string .Empty);

                 builder.Append(str3);

                  builder.Append(str5);

                 str3 =  "," ;

             }

             MessageSignature += builder.ToString() +  "/n" ;

         }

         MessageSignature += GetCanonicalizedResourceVersion2(requesturi, AccountName);

         //   开始创建签名

         byte [] SignatureBytes = System.Text.Encoding .UTF8.GetBytes(MessageSignature);

         System.Security.Cryptography.HMACSHA256   SHA256 =  new System.Security.Cryptography.HMACSHA256 (Convert .FromBase64String(AccountSharedKey));

         //   创建 Authorization HTTP 消息头的值

         String   AuthorizationHeader =  "SharedKey "   + AccountName +  ":"   +  Convert .ToBase64String(SHA256.ComputeHash(SignatureBytes));

         //   把编码后的签名加入到 Authorization HTTP 消息头中

         Request.Headers.Add("Authorization" , AuthorizationHeader);

          //   获取返回消息

         using   (HttpWebResponse   response = (HttpWebResponse )Request.GetResponse())

         {

             if   (response.StatusCode ==  HttpStatusCode .OK)

             {

                 //   服务器返回成功消息

                 using   (Stream   stream = response.GetResponseStream())

                 {

                     using   (StreamReader   sr =  new   StreamReader (stream))

                     {

                         var   s = sr.ReadToEnd();

                         //   输出返回消息

                          Console .WriteLine(s);

                     }

                 }

             }

             else

             {

                 //  这里可以抛出异常信息

             }

         }

         Console .ReadLine();

     }

     static   ArrayList   GetHeaderValues(NameValueCollection   headers,  string   headerName)

     {

         ArrayList   list =  new   ArrayList ();

         string [] values = headers.GetValues(headerName);

         if   (values !=  null )

         {

             foreach   (string   str  in   values)

             {

                 list.Add(str.TrimStart(new   char [0]));

             }

         }

         return   list;

     }

     static   string   GetCanonicalizedResourceVersion2(Uri   address,  string   accountName)

     {

         StringBuilder   builder =  new   StringBuilder ("/" );

         builder.Append(accountName);

         builder.Append(address.AbsolutePath);

         CanonicalizedString   str =  new   CanonicalizedString (builder.ToString());

         NameValueCollection   values =  HttpUtility .ParseQueryString(address.Query);

         NameValueCollection   values2 =  new   NameValueCollection ();

         foreach   (string   str2  in   values.Keys)

         {

             ArrayList   list =  new   ArrayList (values.GetValues(str2));

             list.Sort();

             StringBuilder   builder2 =  new   StringBuilder ();

              foreach   (object   obj2  in   list)

             {

                 if   (builder2.Length > 0)

                 {

                     builder2.Append("," );

                 }

                 builder2.Append(obj2.ToString());

             }

             values2.Add((str2 ==  null ) ? str2 : str2.ToLowerInvariant(), builder2.ToString());

         }

         ArrayList   list2 =  new   ArrayList (values2.AllKeys);

         list2.Sort();

         foreach   (string   str3  in   list2)

         {

             StringBuilder   builder3 =  new   StringBuilder (string .Empty);

             builder3.Append(str3);

             builder3.Append(":" );

             builder3.Append(values2[str3]);

             str.AppendCanonicalizedElement(builder3.ToString());

         }

         return   str.Value;

     }

}

步骤五:观察并分析代码

我们首先观察下面三行代码:

const   string   bloburi =  @"http://127.0.0.1:10000/devstoreaccount1" ;

const   string   accountname =  "devstoreaccount1" ;

const   string   key =  "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" ;

这三行代码定义了 Blob Storage服务端口,我们使用的账户名和密码。由于使用的是本地模拟的 Storage,所以必须使用固定的端口地址,用户名以及密码。可以参考Development Storage与 Windows Azure Storage Services的不同之处获取更多信息。

在代码中,我们使用 HttpWebRequest 构造并发送 HTTP请求。由于我们的例子中使用的是 List Blobs API我们需要查阅List Blobs对该 API的规定构造符合规定的 HTTP请求。

在规定中说明了如果该 container没有被设置为允许匿名访问,那么必须由于账户拥有者调用该 API才能返回结果。要这样做必须添加 Authorization HTTP消息头。我们必须严格按照Authentication Schemes规定的格式来生成该 HTTP消息头。

步骤六:运行程序

如果一切正常,你将会看到 Console程序输出如下信息,内容为名为 helloworld的 Container中所有 Blob的信息: