أفضل الممارسات باستخدام خدمات ويب واجهة برمجة التطبيقات للمنطقة الزمنية

خدمات الويب في "منصة خرائط Google" هي مجموعة من واجهات HTTP لـ Google الخدمات التي توفر بيانات جغرافية لتطبيقات الخرائط.

يصف هذا الدليل بعض الممارسات الشائعة المفيدة في إعداد خدمة ويب الطلبات ومعالجة استجابات الخدمة. يُرجى الرجوع إلى دليل المطوّر. للاطّلاع على المستندات الكاملة الخاصة بواجهة برمجة تطبيقات Time Zone.

ما المقصود بخدمة الويب؟

خدمات الويب في Google Maps Platform هي واجهة لطلب بيانات Maps API من والخدمات الخارجية واستخدام البيانات ضمن تطبيقات الخرائط. هذه الخدمات مصمّمة للاستخدام مع الخريطة، وفقًا قيود الترخيص في بنود خدمة Google Maps Platform

تستخدم خدمات الويب لـ Maps APIs طلبات HTTP(S) لعناوين URL محددة و/أو تمرير معلمات عناوين URL و/أو بيانات POST بتنسيق JSON كوسيطات للخدمات. بشكل عام، تعرض هذه الخدمات بيانات بتنسيق نص الاستجابة إما بتنسيق JSON أو XML للتحليل و/أو المعالجة من خلال طلبك.

عادةً ما يكون الطلب النموذجي لواجهة برمجة التطبيقات Time Zone API النموذج التالي:

https://maps.googleapis.com/maps/api/timezone/output?parameters

حيث يشير output إلى تنسيق الرد (عادةً json أو xml).

ملاحظة: تتطلب جميع تطبيقات Time Zone API المصادقة. مزيد من المعلومات عن بيانات اعتماد المصادقة

الوصول إلى طبقة المقابس الآمنة (SSL)/بروتوكول أمان طبقة النقل (TLS)

يجب استخدام HTTPS لجميع طلبات "منصة خرائط Google" التي تستخدم مفاتيح واجهة برمجة التطبيقات أو تحتوي على مستخدم البيانات. قد يتم رفض الطلبات المقدَّمة عبر HTTP والتي تحتوي على بيانات حسّاسة.

إنشاء عنوان URL صالح

قد تعتقد أن عبارة "صالح" عنوان URL واضح تمامًا، ولكنه هذا ليس هو الحال تمامًا. عنوان URL يتم إدخاله في شريط عناوين في المتصفح، على سبيل المثال، رموز خاصة (مثل "上海+中國") يحتاج المتصفح إلى الترجمة داخليًا هذه الأحرف إلى ترميز مختلف قبل الإرسال. باستخدام الرمز المميّز نفسه، أي رمز ينشئ إدخال UTF-8 أو يقبله عناوين URL التي تحتوي على حروف UTF-8 على أنها "صالحة"، إلا أنها قد تحتاج أيضًا لترجمة تلك الأحرف قبل إرسالها إلى خادم ويب. تُسمى هذه العملية ترميز عنوان URL أو ترميز النسبة المئوية

الرموز الخاصة

نحتاج إلى ترجمة الرموز الخاصة لأننا يجب أن تتوافق جميع عناوين URL مع البنية التي يحددها الزي الرسمي مواصفات معرّفات الموارد (URI) ويعني ذلك في الواقع أنّ عناوين URL على مجموعة فرعية خاصة فقط من أحرف ASCII: الاسم الرموز الأبجدية الرقمية وبعض الأحرف المحجوزة للاستخدام كعنصر تحكم داخل عناوين URL. يلخص هذا الجدول هذه الأحرف:

ملخّص أحرف عنوان URL الصالحة
تعيينالأحرفاستخدام عنوان URL
أحرف أبجدية رقمية ج ج ج ح n o p q r s u v w x y z متقدم لا شيء 0 1 2 3 4 5 6 7 8 9 سلاسل نصية واستخدام المخطط (http) والمنفذ (8080) وما إلى ذلك
غير محجوز - _ . ~ سلاسل نصية
تم الحجز ! * ( ) ; : @ & = + $ , / ? % # [ ] أحرف التحكّم و/أو السلاسل النصية

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

  • الأحرف التي تريد التعامل معها موجودة خارج المحددة أعلاه. على سبيل المثال، الأحرف في اللغات الأجنبية مثل 上海+中國، يجب ترميزها باستخدام فوق الأحرف. حسب الاصطلاحات المشهورة، المساحات (التي غير مسموح بها ضمن عناوين URL) غالبًا باستخدام علامة الجمع بالإضافة إلى حرف واحد ('+').
  • توجد الأحرف ضمن المجموعة أعلاه كأحرف محجوزة، ولكن يجب استخدامها حرفيًا. على سبيل المثال، يتم استخدام ? ضمن عناوين URL للإشارة إلى بداية سلسلة الاستعلام؛ إذا كنت ترغب في استخدام سلسلة "? والأسرار" ستحتاج إلى ترميز حرف واحد ('?').

تم ترميز جميع الأحرف المراد ترميزها باستخدام عنوان URL باستخدام حرف '%' وحرف ست عشري من حرفين تتجاوب مع حرف UTF-8 الخاص بها. على سبيل المثال: سيتم ترميز 上海+中國 في UTF-8 بعنوان URL على النحو التالي: %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B تشير رسالة الأشكال البيانية سيتم ترميز السلسلة ? and the Mysterians بعنوان URL على النحو التالي: %3F+and+the+Mysterians أو %3F%20and%20the%20Mysterians.

الأحرف الشائعة التي تحتاج إلى ترميز

بعض الأحرف الشائعة التي يجب ترميزها هي:

حرف غير آمن قيمة مشفّرة
مسافة %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

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

بالإضافة إلى ذلك، تقتصر عناوين URL على 16384 حرفًا لجميع خدمات الويب على "منصة خرائط Google". وواجهات برمجة تطبيقات الويب الثابتة. في معظم الخدمات، نادرًا ما يتم تجاوز هذا العدد من الأحرف. ومع ذلك، ملاحظة: تتضمن خدمات معيّنة عدة معلَمات قد تؤدي إلى إنشاء عناوين URL طويلة.

استخدام مهذب لـ Google APIs

يمكن لعملاء واجهة برمجة التطبيقات ذوي التصميم السيئ وضع حمل أكبر من اللازم على كل من الإنترنت خوادم Google. يحتوي هذا القسم على بعض أفضل الممارسات لعملاء واجهات برمجة التطبيقات. تتم متابعته حاليًا يمكن أن تساعدك أفضل الممارسات هذه في تجنّب حظر تطبيقك بسبب إساءة الاستخدام واجهات برمجة التطبيقات.

تراجع أسي

في حالات نادرة، قد يحدث خطأ أثناء تنفيذ طلبك؛ قد تتلقّى HTTP 4XX أو 5XX أو ربما يخفق اتصال TCP في مكان ما بين البرنامج ونظام Google الخادم. وغالبًا ما يكون من المفيد إعادة محاولة الطلب فقد ينجح طلب المتابعة عند إخفاق الطلب الأصلي. ومع ذلك، من المهم عدم مجرد تكرار تقديم الطلبات إلى خوادم Google بشكل متكرر. ويمكن أن يؤدي سلوك التكرار هذا إلى زيادة الحمل على شبكة بين عميلك وGoogle مما يتسبب في مشكلات للعديد من الأطراف.

الطريقة الأفضل هي إعادة المحاولة مع زيادة التأخيرات بين المحاولات. عادةً ما يزداد التأخير باستخدام عامل مضاعف مع كل محاولة، وهو أسلوب يُعرف باسم رقود أسي:

على سبيل المثال، جرِّب تطبيقًا يريد تقديم هذا الطلب إلى واجهة برمجة التطبيقات Time Zone API

https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=1331161200&key=YOUR_API_KEY

يوضح مثال بايثون التالي كيفية تقديم الطلب باستخدام خوارزمية الرقود الأسي الثنائي:

import json
import time
import urllib.error
import urllib.parse
import urllib.request

# The maps_key defined below isn't a valid Google Maps API key.
# You need to get your own API key.
# See https://developers.google.com/maps/documentation/timezone/get-api-key
API_KEY = "YOUR_KEY_HERE"
TIMEZONE_BASE_URL = "https://maps.googleapis.com/maps/api/timezone/json"


def timezone(lat, lng, timestamp):

    # Join the parts of the URL together into one string.
    params = urllib.parse.urlencode(
        {"location": f"{lat},{lng}", "timestamp": timestamp, "key": API_KEY,}
    )
    url = f"{TIMEZONE_BASE_URL}?{params}"

    current_delay = 0.1  # Set the initial retry delay to 100ms.
    max_delay = 5  # Set the maximum retry delay to 5 seconds.

    while True:
        try:
            # Get the API response.
            response = urllib.request.urlopen(url)
        except urllib.error.URLError:
            pass  # Fall through to the retry loop.
        else:
            # If we didn't get an IOError then parse the result.
            result = json.load(response)

            if result["status"] == "OK":
                return result["timeZoneId"]
            elif result["status"] != "UNKNOWN_ERROR":
                # Many API errors cannot be fixed by a retry, e.g. INVALID_REQUEST or
                # ZERO_RESULTS. There is no point retrying these requests.
                raise Exception(result["error_message"])

        if current_delay > max_delay:
            raise Exception("Too many retry attempts.")

        print("Waiting", current_delay, "seconds before retrying.")

        time.sleep(current_delay)
        current_delay *= 2  # Increase the delay each time we retry.


if __name__ == "__main__":
    tz = timezone(39.6034810, -119.6822510, 1331161200)
    print(f"Timezone: {tz}")

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

الطلبات المتزامنة

يمكن أن تبدو الأعداد الكبيرة من الطلبات المتزامنة إلى واجهات برمجة تطبيقات Google وكأنها جدول هجوم الحرمان من الخدمات (DDoS) على بنية Google الأساسية، وسيتم التعامل معه وفقًا لذلك. إلى لتجنُّب حدوث ذلك، عليك التأكّد من عدم مزامنة طلبات البيانات من واجهة برمجة التطبيقات بين العملاء.

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

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

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

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

معالجة الردود

يتناول هذا القسم كيفية استخراج هذه القيم ديناميكيًا من استجابات خدمات الويب.

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

يعتمد نظام التحليل الذي تستخدمه على ما إذا كنت تقوم بإرجاع بتنسيق XML أو JSON. استجابات JSON، التي تكون في شكل قد تتم معالجة كائنات JavaScript ضمن JavaScript نفسها. على العميل. يجب معالجة استجابات XML باستخدام معالج XML ولغة استعلام XML لمعالجة العناصر داخل تنسيق XML. نستخدم XPath في الأمثلة التالية، حيث إنها متاحة عادةً في معالجة XML المكتبات.

معالجة XML باستخدام XPath

XML هو تنسيق معلومات منظمة وواضحة نسبيًا يُستخدم تبادل البيانات. رغم أنه ليس بسيطًا مثل JSON أو XML يدعم المزيد من اللغات والأدوات الأكثر فعالية. رمز لـ معالجة XML في Java، على سبيل المثال، مضمنة في javax.xml حزمة.

عند معالجة استجابات XML، عليك استخدام ملف لغة الاستعلام لتحديد العُقد داخل مستند XML، بدلاً من من افتراض أن العناصر تكمن في مواضع مطلقة داخل ترميز XML: XPath هي بناء جملة لغة لوصف العُقد والعناصر بشكل فريد داخل مستند XML. تتيح لك تعبيرات XPath تحديد محتوى معين في مستند استجابة XML.

تعبيرات XPath

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

يستخدم XPath التعبيرات لاختيار عناصر داخل XML المستند، باستخدام بناء جملة مشابه لتلك المستخدمة في مسارات الدليل. تحدد هذه التعبيرات عناصر داخل مستند XML شجرة، وهي شجرة هرمية مشابهة لشجرة نموذج العناصر. بوجه عام، تتسم تعبيرات XPath بأنها جشعة، مما يشير إلى أنها سيطابق جميع العُقد التي تطابق المعايير المتوفرة.

سنستخدم ملف XML المجرد التالي لتوضيح الأمثلة:

<WebServiceResponse>
 <status>OK</status>
 <result>
  <type>sample</type>
  <name>Sample XML</name>
  <location>
   <lat>37.4217550</lat>
   <lng>-122.0846330</lng>
  </location>
 </result>
 <result>
  <message>The secret message</message>
 </result>
</WebServiceResponse>

تحديد العقدة في التعبيرات

تختار اختيارات XPath العُقد. العقدة الأساسية المستند بأكمله. يمكنك اختيار هذه العقدة باستخدام التعبير الخاص "/". لاحظ أن الجذر العقدة ليست العقدة ذات المستوى الأعلى في مستند XML، في الواقع، فإنه يوجد مستوى واحد فوق عنصر المستوى الأعلى هذا ويتضمن بها.

تمثل عُقد العناصر العناصر المختلفة داخل ملف XML شجرة الوثيقة. عنصر <WebServiceResponse>، على سبيل المثال، عنصر المستوى الأعلى الذي يتم إرجاعه في نموذج الخدمة أعلاه. ويمكنك اختيار عُقد فردية إما من خلال مسارات مطلقة أو نسبية، يشار إليها بوجود أو عدم وجود بادئة "/" الحرف.

  • المسار المطلق: "/WebServiceResponse/result" يختار التعبير جميع العُقد الـ <result> التي هم أطفال <WebServiceResponse> العقدة. (لاحظ أن كلا هذين العنصرين ينحدران من الجذر) العقدة "/").
  • المسار النسبي من السياق الحالي: التعبير "result" تتطابق مع أي <result> والعناصر ضمن السياق الحالي. بشكل عام، لا ينبغي أن تقلق بشأن السياق، فعادةً ما تقوم بمعالجة بيانات الويب نتائج الخدمة من خلال تعبير واحد.

يمكن زيادة أي من هذين التعبيرين من خلال جمع لمسار حرف بدل، يشار إليه بشرطة مائلة مزدوجة ("//"). يشير حرف البدل هذا إلى أنه قد لا تتطابق عناصر أو أكثر في مسار متداخل. تعبير XPath "//formatted_address"، على سبيل المثال، مطابقة مع جميع عُقد هذا الاسم في المستند الحالي. سيتطابق التعبير //viewport//lat مع الكل عناصر <lat> التي يمكنها تتبُّع <viewport> بصفتك أحد الوالدين.

بشكل افتراضي، تتطابق تعبيرات XPath مع جميع العناصر. يمكنك فرض قيود على التعبير لمطابقة عنصر معين من خلال توفير predicate، المحاط بقوسين مربعين ([]). مسار XPath التعبير "/GeocodeResponse/result[2] يعرض دائمًا والنتيجة الثانية، على سبيل المثال.

نوع التعبير
Root node
تعبير XPath: "/"
الاختيار:
    <WebServiceResponse>
     <status>OK</status>
     <result>
      <type>sample</type>
      <name>Sample XML</name>
      <location>
       <lat>37.4217550</lat>
       <lng>-122.0846330</lng>
      </location>
     </result>
     <result>
      <message>The secret message</message>
     </result>
    </WebServiceResponse>
    
المسار المطلق
تعبير XPath: "/WebServiceResponse/result"
الاختيار:
    <result>
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    </result>
    <result>
     <message>The secret message</message>
    </result>
    
مسار يتضمّن حرف بدل
تعبير XPath: "/WebServiceResponse//location"
الاختيار:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
مسار مع عدّاد
تعبير XPath: "/WebServiceResponse/result[2]/message"
الاختيار:
    <message>The secret message</message>
    
جميع العناصر الثانوية المباشرة لأول result
تعبير XPath: "/WebServiceResponse/result[1]/*"
الاختيار:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
name من result الذي يكون نصه type هو "عيّنة".
تعبير XPath: "/WebServiceResponse/result[type/text()='sample']/name"
الاختيار:
    Sample XML
    

من المهم ملاحظة أنه عند تحديد العناصر، فإنك تحدد العُقد، وليس فقط النص الموجود داخل تلك الكائنات. بشكل عام، هناك حاجة إلى التكرار على جميع العُقد المتطابقة واستخراج النص. إِنْتَ قد تتطابق أيضًا مع العُقد النصية مباشرةً؛ راجِع العُقد النصية. أدناه.

يُرجى العِلم أنّ XPath يتوافق أيضًا مع عُقد السمات. وَلَكِنْ تقدّم جميع خدمات الويب في "خرائط Google" عناصر بدون سمات، ومطابقة السمات ليس ضروريًا.

تحديد النص في التعبيرات

يتم تحديد نص داخل مستند XML في تعبيرات XPath من خلال عامل تشغيل عقدة نص. عامل التشغيل هذا "text()" تشير إلى استخراج النص من العقدة المشار إليها. على سبيل المثال: تعبير XPath "//formatted_address/text()" سوف عرض كل النص خلال <formatted_address> عناصر.

نوع التعبير
جميع العُقد النصية (بما في ذلك المسافة البيضاء)
تعبير XPath: "//text()"
الاختيار:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
تحديد النص
تعبير XPath: "/WebServiceRequest/result[2]/message/text()"
الاختيار:
    The secret message
    
اختيار حساس للسياق
تعبير XPath: "/WebServiceRequest/result[type/text() = 'sample']/name/text()"
الاختيار:
    Sample XML
    

أو يمكنك تقييم تعبير وعرض مجموعة ثم نكرر "مجموعة العُقد" هذه، واستخراج لكل عقدة. نستخدم هذا المنهج في المثال التالي.

لمزيد من المعلومات حول XPath، يمكنك الرجوع إلى مواصفات XPath W3C.

تقييم XPath في Java

تتوفر في Java دعم كبير لتحليل XML واستخدام تعبيرات XPath ضمن حزمة javax.xml.xpath.*. لهذا السبب، يستخدم الرمز النموذجي في هذا القسم Java توضيح كيفية التعامل مع XML وتحليل البيانات من استجابات خدمة XML.

لاستخدام XPath في رمز Java، يجب أولاً إنشاء مثيل مثيل XPathFactory واستدعاء newXPath() في هذا المصنع لإنشاء عنصر XPath . ويمكن لهذا العنصر بعد ذلك معالجة ملف XML الذي تم تمريره. وتعبيرات XPath باستخدام الطريقة evaluate().

عند تقييم تعبيرات XPath، احرص على تكرار على أي "مجموعات عُقد" محتملة التي يمكن إرجاعها. لأن هذه يتم عرض النتائج كعُقد DOM في رمز Java، يجب الحصول على هذه القيم المتعددة داخل كائن NodeList التكرار خلال هذا الكائن لاستخراج أي نص أو قيم من تلك العُقد.

يوضّح الرمز التالي كيفية إنشاء XPath وتعيين XML وتعبير XPath، ثم تقييم لطباعة المحتوى ذي الصلة.

import org.xml.sax.InputSource;
import org.w3c.dom.*;
import javax.xml.xpath.*;
import java.io.*;

public class SimpleParser {

  public static void main(String[] args) throws IOException {

	XPathFactory factory = XPathFactory.newInstance();

    XPath xpath = factory.newXPath();

    try {
      System.out.print("Web Service Parser 1.0\n");

      // In practice, you'd retrieve your XML via an HTTP request.
      // Here we simply access an existing file.
      File xmlFile = new File("XML_FILE");

      // The xpath evaluator requires the XML be in the format of an InputSource
	  InputSource inputXml = new InputSource(new FileInputStream(xmlFile));

      // Because the evaluator may return multiple entries, we specify that the expression
      // return a NODESET and place the result in a NodeList.
      NodeList nodes = (NodeList) xpath.evaluate("XPATH_EXPRESSION", inputXml, XPathConstants.NODESET);

      // We can then iterate over the NodeList and extract the content via getTextContent().
      // NOTE: this will only return text for element nodes at the returned context.
      for (int i = 0, n = nodes.getLength(); i < n; i++) {
        String nodeString = nodes.item(i).getTextContent();
        System.out.print(nodeString);
        System.out.print("\n");
      }
    } catch (XPathExpressionException ex) {
	  System.out.print("XPath Error");
    } catch (FileNotFoundException ex) {
      System.out.print("File Error");
    }
  }
}