استدعاء عمليات واجهة برمجة تطبيقات REST مع تفويض المفتاح المشترك

توضح هذه المقالة كيفية استدعاء عملية Azure Storage REST API عن طريق إنشاء طلب REST معتمد باستخدام C#. بعد أن تتعلم كيفية استدعاء عملية REST API ل Blob Storage، يمكنك استخدام خطوات مماثلة لأي عملية Azure Storage REST أخرى.

المتطلبات الأساسية

يسرد نموذج التطبيق حاويات الكائن الثنائي كبير الحجم لحساب تخزين. لتجربة التعليمة البرمجية في هذه المقالة، تحتاج إلى العناصر التالية:

  • تثبيت Visual Studio وتضمين حمل عمل تطوير Azure. تم إنشاء هذا المثال باستخدام Visual Studio 2019. إذا كنت تستخدم إصدارا مختلفا، فقد تختلف الإرشادات قليلا.

  • اشتراك Azure. في حال لم يكن لديك اشتراك Azure، فأنشئ حساباً مجانيّاً قبل البدء.

  • حساب تخزين لأغراض عامة. إذا لم يكن لديك حساب تخزين، فيمكنك إنشاء حساب تخزين.

  • يوضح المثال الوارد في هذه المقالة كيفية سرد الحاويات في حساب تخزين. لمشاهدة الإخراج، أضف بعض حاويات الكائن الثنائي كبير الحجم إلى حساب التخزين قبل البدء.

قم بتنزيل نموذج الطلب

نموذج التطبيق هو تطبيق وحدة تحكم مكتوب بلغة C#‎.

استخدم git لتنزيل نسخة من التطبيق إلى بيئة التطوير الخاصة بك.

git clone https://github.com/Azure-Samples/storage-dotnet-rest-api-with-auth.git

يستنسخ هذا الأمر المستودع إلى مجلد git المحلي. لفتح حل Visual Studio، انتقل إلى المجلد storage-dotnet-rest-api-with-auth وافتح StorageRestApiAuth.sln.

عن REST

نقل الحالة التمثيلية (REST) هو بنية تمكنك من التفاعل مع خدمة عبر بروتوكول إنترنت، مثل HTTP/HTTPS. REST مستقل عن البرنامج الذي يعمل على الخادم أو العميل. يمكن استدعاء واجهة برمجة تطبيقات REST من أي نظام أساسي يدعم HTTP/HTTPS. يمكنك كتابة تطبيق يعمل على جهاز Mac أو Windows أو Linux أو هاتف Android أو جهاز لوحي أو iPhone أو iPod أو موقع ويب، واستخدام نفس واجهة برمجة تطبيقات REST لجميع هذه الأنظمة الأساسية.

يتكون استدعاء واجهة برمجة تطبيقات REST من طلب مقدم من العميل، واستجابة يتم إرجاعها بواسطة الخدمة. في الطلب، يمكنك إرسال عنوان محدد مواقع الويب يحتوي على معلومات حول العملية التي تريد الاتصال بها، والمورد المطلوب العمل عليه، وأي معلمات ورؤوس استعلام، واعتمادا على العملية التي تم استدعاؤها، حمولة البيانات. تتضمن الاستجابة من الخدمة رمز حالة ومجموعة من رؤوس الاستجابة، واعتمادا على العملية التي تم استدعاؤها، حمولة من البيانات.

نبذة عن نموذج التطبيق

يسرد نموذج التطبيق الحاويات الموجودة في حساب تخزين. بمجرد فهم كيفية ارتباط المعلومات الموجودة في وثائق واجهة برمجة تطبيقات REST بالتعليمات البرمجية الفعلية الخاصة بك، يسهل معرفة استدعاء REST الأخرى.

إذا نظرت إلى واجهة برمجة تطبيقات REST لخدمة الكائن الثنائي كبير الحجم، فسترى جميع العمليات التي يمكنك تنفيذها على تخزين الكائن الثنائي كبير الحجم. مكتبات عميل التخزين هي برامج تضمين حول واجهات برمجة تطبيقات REST، ما يجعل من السهل الوصول إلى موارد التخزين دون استخدام واجهات برمجة تطبيقات REST مباشرة. ومع ذلك، قد تحتاج في بعض الأحيان إلى استخدام واجهة برمجة تطبيقات REST بدلا من مكتبة عميل التخزين.

عملية حاويات القائمة

تركز هذه المقالة على عملية حاويات القائمة. تساعدك المعلومات التالية على فهم بعض الحقول في الطلب والاستجابة.

طريقة الطلب: GET. هذا الفعل هو أسلوب HTTP الذي تحدده كخاصية لكائن الطلب. تتضمن القيم الأخرى لهذا الفعل HEAD وPUT وDELETE، اعتمادا على واجهة برمجة التطبيقات التي تتصل بها.

طلب معرف الموارد المنتظم: https://myaccount.blob.core.windows.net/?comp=list. يتم إنشاء عنوان معرف الموارد المنتظم للطلب من نقطة https://myaccount.blob.core.windows.net نهاية حساب تخزين الكائن الثنائي كبير الحجم وسلسلة الموارد /?comp=list.

معلمات معرف الموارد المنتظم: هناك معلمات استعلام إضافية يمكنك استخدامها عند الاتصال بـ ListContainers. اثنين من هذه المعلمات هي مهلة للاستدعاء (بالثواني) والبادئة، والتي تستخدم للتصفية.

معلمة أخرى مفيدة هي maxresults: إذا كان هناك المزيد من الحاويات المتوفرة أكثر من هذه القيمة، فسيحتوي نص الاستجابة على عنصر NextMarker يشير إلى الحاوية التالية للعودة إلى الطلب التالي. لاستخدام هذه الميزة، يمكنك توفير قيمة NextMarker كمعلمة علامة في عنوان معرف الموارد المنتظم عند إجراء الطلب التالي. عند استخدام هذه الميزة، فإنه مماثل لترحيل عبر النتائج.

لاستخدام معلمات إضافية، قم بإلحاقها بسلسلة الموارد ذات القيمة، مثل هذا المثال:

/?comp=list&timeout=60&maxresults=100

رؤوس الطلبات: يسرد هذا القسم رؤوس الطلبات المطلوبة والاختيارية. ثلاثة من الرؤوس مطلوبة: التفويضرأس، x-ms-date (يحتوي على التوقيت العالمي المنسق للطلب)، وx-ms-version (يحدد إصدار واجهة برمجة تطبيقات REST للاستخدام). يعد تضمين x-ms-client-request-id في العناوين اختياريا. يمكنك تعيين قيمة هذا الحقل إلى أي شيء، ويتم كتابتها إلى سجلات تحليلات التخزين عند تمكين التسجيل.

نص الطلب: لا يوجد نص طلب ل ListContainers. يتم استخدام نص الطلب على جميع عمليات PUT عند تحميل الكائنات الثنائية كبيرة الحجم، بما في ذلك SetContainerAccessPolicy. يسمح لك نص الطلب بإرسال قائمة XML بنهج الوصول المخزنة لتطبيقها. تتم مناقشة سياسات الوصول المخزنة في المقالة استخدام توقيعات الوصول المشترك (SAS).

رمز حالة الاستجابة: يخبرك بأي رموز حالة تحتاج إلى معرفتها. في هذا المثال، رمز حالة HTTP من 200 على ما يرام. للحصول على قائمة كاملة برموز حالة HTTP، راجع تعريفات رمز الحالة. للاطلاع على رموز الخطأ الخاصة بواجهات برمجة تطبيقات Storage REST، راجع رموز خطأ واجهة برمجة تطبيقات REST الشائعة

رؤوس الاستجابة: وتشمل هذه نوع المحتوى؛ x-ms-request-id، وهو معرف الطلب الذي مررت به؛ x-ms-version، والذي يشير إلى إصدار خدمة الكائن الثنائي كبير الحجم المستخدمة؛ والتاريخ، الموجود بالتوقيت العالمي المنسق ويخبر بالوقت الذي تم فيه تقديم الطلب.

نص الاستجابة: هذا الحقل عبارة عن بنية XML توفر البيانات المطلوبة. في هذا المثال، تكون الاستجابة عبارة عن قائمة بالحاويات وخصائصها.

إنشاء طلب REST

للأمان عند التشغيل في الإنتاج، استخدم دائما HTTPS بدلا من HTTP. لأغراض هذا التمرين، نستخدم HTTP حتى تتمكن من عرض بيانات الطلب والاستجابة. لعرض معلومات الطلب والاستجابة في مكالمات REST الفعلية، يمكنك تنزيل Fiddler أو تطبيق مماثل. في حل Visual Studio، يتم ترميز اسم حساب التخزين ومفتاحه في الفصل. الأسلوب ListContainersAsyncREST بتمرير اسم حساب التخزين ومفتاح حساب التخزين إلى الأساليب المستخدمة لإنشاء المكونات المختلفة لطلب REST. في تطبيق العالم الحقيقي، سيكون اسم حساب التخزين ومفتاحه موجودين في ملف تكوين أو متغيرات بيئة أو يتم استردادهما من Azure Key Vault.

في نموذج المشروع، تكون التعليمات البرمجية لإنشاء رأس التفويض في فئة منفصلة. الفكرة هي أنه يمكنك أخذ الفصل بأكمله وإضافته إلى الحل الخاص بك واستخدامه "كما هو". يعمل رمز رأس التفويض لمعظم استدعاءات واجهة برمجة تطبيقات REST إلى Azure Storage.

لإنشاء الطلب، وهو كائن HttpRequestMessage، انتقل إلى ListContainersAsyncREST في Program.cs. خطوات بناء الطلب هي:

  • قم بإنشاء محدد مواقع الويب لاستخدامه للاتصال بالخدمة.
  • إنشاء كائن HttpRequestMessage وتعيين الحمولة. الحمولة فارغة لـ ListContainersAsyncREST لأننا لا نمرر أي شيء.
  • أضف رؤوس الطلبات لإصدار x-ms-date وx-ms-version.
  • احصل على رأس التفويض وأضفه.

بعض المعلومات الأساسية التي تحتاجها:

  • بالنسبة ل ListContainers، فإن الطريقة هي GET. يتم تعيين هذه القيمة عند إنشاء الطلب.
  • المورد هو جزء الاستعلام من معرف الموارد المنتظم الذي يشير إلى واجهة برمجة التطبيقات التي يتم استدعاؤها، وبالتالي فإن القيمة هي /?comp=list. كما ذكرنا سابقا، يوجد المورد في صفحة الوثائق المرجعية التي تعرض معلومات حول واجهة برمجة تطبيقات ListContainers.
  • يتم إنشاء معرف الموارد المنتظم عن طريق إنشاء نقطة نهاية خدمة الكائن الثنائي كبير الحجم لحساب التخزين هذا وتسلسل المورد. قيمة طلب معرف الموارد المنتظم ينتهي بها الأمر إلى أن تكون http://contosorest.blob.core.windows.net/?comp=list.
  • بالنسبة إلى ListContainers، يكون requestBody فارغا ولا توجد رؤوس إضافية.

قد تحتوي واجهات برمجة التطبيقات المختلفة على معلمات أخرى لتمريرها مثل ifMatch. مثال على المكان الذي يمكنك استخدام ifMatch فيه عند الاتصال بـ PutBlob. في هذه الحالة، يمكنك تعيين ifMatch إلى eTag، وتقوم بتحديث النقطة فقط إذا كانت العلامة الإلكترونية التي تقدمها تتطابق مع eTag الحالية على النقطة. إذا قام شخص آخر بتحديث الكائن الثنائي كبير الحجم منذ استرداد eTag، فلن يتم تجاوز تغييره.

أولا، قم بتعيين uri و requestPayload.

// Construct the URI. It will look like this:
//   https://myaccount.blob.core.windows.net/resource
String uri = string.Format("http://{0}.blob.core.windows.net?comp=list", storageAccountName);

// Provide the appropriate payload, in this case null.
//   we're not passing anything in.
Byte[] requestPayload = null;

بعد ذلك، قم بإنشاء الطلب، وتعيين الطريقة إلى GET توفير عنوان معرف الموارد المنتظم.

// Instantiate the request message with a null payload.
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri)
{ Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{

أضف رؤوس الطلبات لـ x-ms-date و x-ms-version. هذا المكان في الرمز هو أيضا المكان الذي تضيف فيه أي رؤوس طلبات إضافية مطلوبة للمكالمة. في هذا المثال، لا توجد رؤوس إضافية. مثال على واجهة برمجة التطبيقات التي تمر في رؤوس إضافية هي عملية تعيين قائمة التحكم بالوصول للحاويات. تضيف استدعاء واجهة برمجة التطبيقات هذا رأسا يسمى "x-ms-blob-public-access" وقيمة مستوى الوصول.

// Add the request headers for x-ms-date and x-ms-version.
DateTime now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R", CultureInfo.InvariantCulture));
httpRequestMessage.Headers.Add("x-ms-version", "2017-07-29");
// If you need any additional headers, add them here before creating
//   the authorization header.

استدعاء الطريقة التي تنشئ رأس التفويض وإضافته إلى رؤوس الطلبات. يتم إنشاء عنوان التخويل لاحقا في المقالة. اسم الطريقة هو GetAuthorizationHeader، والذي يمكنك رؤيته في القصاصة البرمجية هذه:

// Get the authorization header and add it.
httpRequestMessage.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(
    storageAccountName, storageAccountKey, now, httpRequestMessage);

في هذه المرحلة، httpRequestMessage يحتوي على طلب REST الكامل مع رؤوس التفويض.

أرسل الطلب

الآن بعد أن قمت بإنشاء الطلب، يمكنك استدعاء أسلوب SendAsync لإرساله إلى Azure Storage. تحقق من أن قيمة رمز حالة الاستجابة هي 200، مما يعني أن العملية قد نجحت. بعد ذلك، قم بتحليل الاستجابة. في هذه الحالة، تحصل على قائمة XML من الحاويات. لنلقِ نظرة على التعليمات البرمجية لاستدعاء طريقة GetRESTRequest لإنشاء الطلب وتنفيذ الطلب ثم فحص الاستجابة لقائمة الحاويات.

    // Send the request.
    using (HttpResponseMessage httpResponseMessage =
      await new HttpClient().SendAsync(httpRequestMessage, cancellationToken))
    {
        // If successful (status code = 200),
        //   parse the XML response for the container names.
        if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
        {
            String xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
            XElement x = XElement.Parse(xmlString);
            foreach (XElement container in x.Element("Containers").Elements("Container"))
            {
                Console.WriteLine("Container name = {0}", container.Element("Name").Value);
            }
        }
    }
}

إذا قمت بتشغيل متلصص شبكة مثل Fiddler عند إجراء المكالمة إلى SendAsync، فيمكنك الاطلاع على معلومات الطلب والاستجابة. دعونا نلقي نظرة. اسم حساب التخزين هو contosorest.

طلب:

GET /?comp=list HTTP/1.1

رؤوس الطلب:

x-ms-date: Thu, 16 Nov 2017 23:34:04 GMT
x-ms-version: 2014-02-14
Authorization: SharedKey contosorest:1dVlYJWWJAOSHTCPGiwdX1rOS8B4fenYP/VrU0LfzQk=
Host: contosorest.blob.core.windows.net
Connection: Keep-Alive

تم إرجاع رمز الحالة ورؤوس الاستجابة بعد التنفيذ:

HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 3e889876-001e-0039-6a3a-5f4396000000
x-ms-version: 2017-07-29
Date: Fri, 17 Nov 2017 00:23:42 GMT
Content-Length: 1511

نص الاستجابة (XML): بالنسبة لعملية "حاويات القائمة"، يعرض هذا قائمة الحاويات وخصائصها.

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults
  ServiceEndpoint="http://contosorest.blob.core.windows.net/">
  <Containers>
    <Container>
      <Name>container-1</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:39:48 GMT</Last-Modified>
        <Etag>"0x8D46CBD5A7C301D"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Container>
    <Container>
      <Name>container-2</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:40:50 GMT</Last-Modified>
        <Etag>"0x8D46CBD7F49E9BD"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Container>
    <Container>
      <Name>container-3</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:41:10 GMT</Last-Modified>
        <Etag>"0x8D46CBD8B243D68"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Container>
    <Container>
      <Name>container-4</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:41:25 GMT</Last-Modified>
        <Etag>"0x8D46CBD93FED46F"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
        </Properties>
      </Container>
      <Container>
        <Name>container-5</Name>
        <Properties>
          <Last-Modified>Thu, 16 Mar 2017 22:41:39 GMT</Last-Modified>
          <Etag>"0x8D46CBD9C762815"</Etag>
          <LeaseStatus>unlocked</LeaseStatus>
          <LeaseState>available</LeaseState>
        </Properties>
      </Container>
  </Containers>
  <NextMarker />
</EnumerationResults>

الآن بعد أن فهمت كيفية إنشاء الطلب والاتصال بالخدمة وتحليل النتائج، دعنا نرى كيفية إنشاء رأس التفويض.

إنشاء رأس التفويض

تلميح

يدعم Azure Storage تكامل Microsoft Entra للكائنات الثنائية كبيرة الحجم وقوائم الانتظار. يوفر معرف Microsoft Entra تجربة أبسط بكثير لتخويل طلب إلى Azure Storage. لمزيد من المعلومات حول استخدام معرف Microsoft Entra لتخويل عمليات REST، راجع التخويل باستخدام معرف Microsoft Entra. للحصول على نظرة عامة حول تكامل Microsoft Entra مع Azure Storage، راجع مصادقة الوصول إلى Azure Storage باستخدام معرف Microsoft Entra.

لمعرفة المزيد حول مفاهيم التخويل، راجع تخويل الطلبات إلى Azure Storage.

نستخلص من هذه المقالة أن هناك حاجة إليها بالضبط ونعرض الرمز.

أولا، استخدم تفويض المفتاح المشترك. يبدو تنسيق رأس التفويض كما يلي:

Authorization="SharedKey <storage account name>:<signature>"  

حقل التوقيع عبارة عن رمز مصادقة رسالة يستند إلى التجزئة (HMAC) تم إنشاؤه من الطلب وتم حسابه باستخدام خوارزمية SHA256، ثم تم ترميزه باستخدام ترميز Base64.

يعرض مقتطف التعليمات البرمجية هذا تنسيق سلسلة توقيع المفتاح المشترك:

StringToSign = VERB + "\n" +  
               Content-Encoding + "\n" +  
               Content-Language + "\n" +  
               Content-Length + "\n" +  
               Content-MD5 + "\n" +  
               Content-Type + "\n" +  
               Date + "\n" +  
               If-Modified-Since + "\n" +  
               If-Match + "\n" +  
               If-None-Match + "\n" +  
               If-Unmodified-Since + "\n" +  
               Range + "\n" +  
               CanonicalizedHeaders +  
               CanonicalizedResource;  

بالنسبة لتخزين الكائنات الثنائية كبيرة الحجم، يمكنك تحديد VERB وmd5 وطول المحتوى والرؤوس الأساسية والمورد الأساسي. يمكنك ترك الآخرين فارغين لهذا المثال، ولكن ضعها \n لتحديد أنها فارغة.

المتعارف عليه هو عملية توحيد البيانات التي لديها أكثر من تمثيل واحد ممكن. في هذه الحالة، تقوم بتوحيد العناوين والمورد. الرؤوس المتعارف عليها هي الرؤوس التي تبدأ ب "x-ms-". المورد المتعارف عليه هو URI للمورد، بما في ذلك اسم حساب التخزين وجميع معلمات الاستعلام (مثل ?comp=list). يتضمن المورد المتعارف عليه أيضا أي معلمات استعلام إضافية قد تكون أضفتها، مثل timeout=60، على سبيل المثال.

لنبدأ بالحقول المتعارف عليها، لأنهما مطلوبان لإنشاء عنوان التخويل.

الرؤوس المحولة

لإنشاء هذه القيمة، استرجع الرؤوس التي تبدأ بـ "x-ms-" وقم بفرزها، ثم قم بتنسيقها في سلسلة من [key:value\n] المثيلات، متسلسلة في سلسلة واحدة. على سبيل المثال، تبدو الرؤوس المحولة كما يلي:

x-ms-date:Fri, 17 Nov 2017 00:44:48 GMT\nx-ms-version:2017-07-29\n

إليك الرمز المستخدم لإنشاء هذا الإخراج:

private static string GetCanonicalizedHeaders(HttpRequestMessage httpRequestMessage)
{
    var headers = from kvp in httpRequestMessage.Headers
        where kvp.Key.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase)
        orderby kvp.Key
        select new { Key = kvp.Key.ToLowerInvariant(), kvp.Value };

    StringBuilder headersBuilder = new StringBuilder();

    foreach (var kvp in headers)
    {
        headersBuilder.Append(kvp.Key);
        char separator = ':';

        // Get the value for each header, strip out \r\n if found, then append it with the key.
        foreach (string headerValue in kvp.Value)
        {
            string trimmedValue = headerValue.TrimStart().Replace("\r\n", string.Empty);
            headersBuilder.Append(separator).Append(trimmedValue);

            // Set this to a comma; this will only be used
            // if there are multiple values for one of the headers.
            separator = ',';
        }

        headersBuilder.Append("\n");
    }

    return headersBuilder.ToString();
}

مورد محول

يمثل هذا الجزء من سلسلة التوقيع حساب التخزين المستهدف بالطلب. تذكر أن معرف الموارد المنتظم للطلب هو http://contosorest.blob.core.windows.net/?comp=list، مع اسم الحساب الفعلي (contosorest في هذه الحالة). في هذا المثال، يتم إرجاع هذا:

/contosorest/\ncomp:list

إذا كان لديك معلمات استعلام، فسيتضمن هذا المثال هذه المعلمات أيضا. إليك التعليمة البرمجية التي تتعامل أيضا مع معلمات الاستعلام الإضافية ومعلمات الاستعلام بقيم متعددة. تذكر أنك تقوم بإنشاء هذا الرمز للعمل مع جميع واجهات برمجة تطبيقات REST. تريد تضمين جميع الاحتمالات، حتى إذا كانت طريقة ListContainers لا تحتاج إليها جميعا.

private static string GetCanonicalizedResource(Uri address, string storageAccountName)
{
    // The absolute path will be "/" because for we're getting a list of containers.
    StringBuilder sb = new StringBuilder("/").Append(storageAccountName).Append(address.AbsolutePath);

    // Address.Query is the resource, such as "?comp=list".
    // This ends up with a NameValueCollection with 1 entry having key=comp, value=list.
    // It will have more entries if you have more query parameters.
    NameValueCollection values = HttpUtility.ParseQueryString(address.Query);

    foreach (var item in values.AllKeys.OrderBy(k => k))
    {
        sb.Append('\n').Append(item.ToLower()).Append(':').Append(values[item]);
    }

    return sb.ToString();
}

الآن بعد تعيين السلاسل المحولة، لنلقِ نظرة على كيفية إنشاء رأس التفويض نفسه. تبدأ بإنشاء سلسلة من توقيع الرسالة بتنسيق StringToSign المعروض مسبقا في هذه المقالة. من الأسهل شرح هذا المفهوم باستخدام التعليقات في التعليمات البرمجية، لذلك هنا، الطريقة النهائية التي ترجع رأس التفويض:

internal static AuthenticationHeaderValue GetAuthorizationHeader(
    string storageAccountName, string storageAccountKey, DateTime now,
    HttpRequestMessage httpRequestMessage, string ifMatch = "", string md5 = "")
{
    // This is the raw representation of the message signature.
    HttpMethod method = httpRequestMessage.Method;
    String MessageSignature = String.Format("{0}\n\n\n{1}\n{5}\n\n\n\n{2}\n\n\n\n{3}{4}",
                method.ToString(),
                (method == HttpMethod.Get || method == HttpMethod.Head) ? String.Empty
                  : httpRequestMessage.Content.Headers.ContentLength.ToString(),
                ifMatch,
                GetCanonicalizedHeaders(httpRequestMessage),
                GetCanonicalizedResource(httpRequestMessage.RequestUri, storageAccountName),
                md5);

    // Now turn it into a byte array.
    byte[] SignatureBytes = Encoding.UTF8.GetBytes(MessageSignature);

    // Create the HMACSHA256 version of the storage key.
    HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(storageAccountKey));

    // Compute the hash of the SignatureBytes and convert it to a base64 string.
    string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));

    // This is the actual header that will be added to the list of request headers.
    AuthenticationHeaderValue authHV = new AuthenticationHeaderValue("SharedKey",
        storageAccountName + ":" + signature);
    return authHV;
}

عند تشغيل هذه التعليمة البرمجية، يبدو MessageSignature الناتج مثل هذا المثال:

GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 17 Nov 2017 01:07:37 GMT\nx-ms-version:2017-07-29\n/contosorest/\ncomp:list

إليك القيمة النهائية لـ AuthorizationHeader:

SharedKey contosorest:Ms5sfwkA8nqTRw7Uury4MPHqM6Rj2nfgbYNvUKOa67w=

رأس التفويض هو آخر رأس يتم وضعه في رؤوس الطلبات قبل نشر الاستجابة.

يغطي ذلك كل ما تحتاج إلى معرفته لتجميع فئة يمكنك من خلالها إنشاء طلب للاتصال بواجهات برمجة تطبيقات REST لخدمات التخزين.

مثال: نقط القائمة

لنلقِ نظرة على كيفية تغيير التعليمات البرمجية لاستدعاء عملية سرد الكيانات الثنائية كبيرة الحجم لحاوية الحاوية-1. هذا الرمز مطابق تقريبا للرمز الخاص بإدراج الحاويات، والاختلافات الوحيدة هي معرف الموارد المنتظم وكيفية تحليل الاستجابة.

إذا نظرت إلى الوثائق المرجعية لـ ListBlobs، فستجد أن الطريقة هي GET وRequestURI هي:

https://myaccount.blob.core.windows.net/container-1?restype=container&comp=list

في ListContainersAsyncREST، قم بتغيير التعليمة البرمجية التي تقوم بتعيين معرف الموارد المنتظم إلى واجهة برمجة التطبيقات لـ ListBlobs. اسم الحاوية هو container-1.

String uri =
    string.Format("http://{0}.blob.core.windows.net/container-1?restype=container&comp=list",
      storageAccountName);

ثم عندما تتعامل مع الاستجابة، قم بتغيير الرمز للبحث عن النقاط بدلا من الحاويات.

foreach (XElement container in x.Element("Blobs").Elements("Blob"))
{
    Console.WriteLine("Blob name = {0}", container.Element("Name").Value);
}

عند تشغيل هذه العينة، تحصل على نتائج مثل ما يلي:

الرؤوس المحولة:

x-ms-date:Fri, 17 Nov 2017 05:16:48 GMT\nx-ms-version:2017-07-29\n

المورد المحول:

/contosorest/container-1\ncomp:list\nrestype:container

توقيع الرسالة:

GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 17 Nov 2017 05:16:48 GMT
  \nx-ms-version:2017-07-29\n/contosorest/container-1\ncomp:list\nrestype:container

عنوان التفويض:

SharedKey contosorest:uzvWZN1WUIv2LYC6e3En10/7EIQJ5X9KtFQqrZkxi6s=

القيم التالية هي من Fiddler:

طلب:

GET http://contosorest.blob.core.windows.net/container-1?restype=container&comp=list HTTP/1.1

رؤوس الطلب:

x-ms-date: Fri, 17 Nov 2017 05:16:48 GMT
x-ms-version: 2017-07-29
Authorization: SharedKey contosorest:uzvWZN1WUIv2LYC6e3En10/7EIQJ5X9KtFQqrZkxi6s=
Host: contosorest.blob.core.windows.net
Connection: Keep-Alive

تم إرجاع رمز الحالة ورؤوس الاستجابة بعد التنفيذ:

HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 7e9316da-001e-0037-4063-5faf9d000000
x-ms-version: 2017-07-29
Date: Fri, 17 Nov 2017 05:20:21 GMT
Content-Length: 1135

نص الاستجابة (XML): تعرض استجابة XML هذه قائمة النقط وخصائصها.

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults
    ServiceEndpoint="http://contosorest.blob.core.windows.net/" ContainerName="container-1">
    <Blobs>
        <Blob>
            <Name>DogInCatTree.png</Name>
            <Properties><Last-Modified>Fri, 17 Nov 2017 01:41:14 GMT</Last-Modified>
            <Etag>0x8D52D5C4A4C96B0</Etag>
            <Content-Length>419416</Content-Length>
            <Content-Type>image/png</Content-Type>
            <Content-Encoding />
            <Content-Language />
            <Content-MD5 />
            <Cache-Control />
            <Content-Disposition />
            <BlobType>BlockBlob</BlobType>
            <LeaseStatus>unlocked</LeaseStatus>
            <LeaseState>available</LeaseState>
            <ServerEncrypted>true</ServerEncrypted>
            </Properties>
        </Blob>
        <Blob>
            <Name>GuyEyeingOreos.png</Name>
            <Properties>
                <Last-Modified>Fri, 17 Nov 2017 01:41:14 GMT</Last-Modified>
                <Etag>0x8D52D5C4A25A6F6</Etag>
                <Content-Length>167464</Content-Length>
                <Content-Type>image/png</Content-Type>
                <Content-Encoding />
                <Content-Language />
                <Content-MD5 />
                <Cache-Control />
                <Content-Disposition />
                <BlobType>BlockBlob</BlobType>
                <LeaseStatus>unlocked</LeaseStatus>
                <LeaseState>available</LeaseState>
                <ServerEncrypted>true</ServerEncrypted>
            </Properties>
            </Blob>
        </Blobs>
    <NextMarker />
</EnumerationResults>

الملخص

في هذه المقالة، تعلمت كيفية تقديم طلب إلى واجهة برمجة تطبيقات REST لتخزين الكائن الثنائي كبير الحجم. باستخدام الطلب، يمكنك استرداد قائمة بالحاويات أو قائمة بالنقاط في حاوية. تعلمت كيفية إنشاء توقيع التفويض لاستدعاء واجهة برمجة تطبيقات REST وكيفية استخدامه في طلب REST. وأخيرا، تعلمت كيفية فحص الاستجابة.

الخطوات التالية