يمكنك تجربة الجيل التالي من ميزات الاتجاهات باستخدام واجهة برمجة تطبيقات المسارات.

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

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

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

ما هي خدمة الويب؟

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

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

ويكون طلب البيانات عادةً من واجهة برمجة التطبيقات للتوجيهات بشكل عام على النحو التالي:

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

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

ملاحظة: تتطلب جميع تطبيقات واجهة برمجة التطبيقات الاتجاهات المصادقة. يمكنك الحصول على مزيد من المعلومات عن بيانات اعتماد المصادقة.

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

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

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

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

الأحرف الخاصة

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

ملخص أحرف عنوان URL الصالحة
تحديدالشخصياتاستخدام عنوان URL
أحرف أبجدية رقمية a c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J L M سلاسل نصية واستخدام المخطّط (http) والمنفذ (8080) وما إلى ذلك
غير محجوز - _ . ~ سلاسل نصية
تم الحجز ! * ' ( ) ; : @ & = + $ , / ? % # [ ] التحكّم في الأحرف و/أو السلاسل النصية

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

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

يتم ترميز كل الأحرف التي سيتم ترميزها باستخدام عنوان URL باستخدام حرف '%' وقيمة سداسية عشرية من حرفين مقابلة لترميز UTF-8. على سبيل المثال، سيتم ترميز 上海+中國 في UTF-8 على النحو التالي: %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 على 8192 حرفًا لجميع خدمات الويب من "منصة خرائط Google" وواجهات برمجة تطبيقات الويب الثابتة. ونادرًا ما يتم الوصول إلى هذا الحد الأقصى المسموح به في معظم الخدمات. ومع ذلك، تجدر الإشارة إلى أنّ بعض الخدمات تحتوي على عدة معلَمات قد تؤدي إلى إنشاء عناوين URL طويلة.

الاستخدام الإضافي لـ Google APIs

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

الرقود الأسي

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

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

على سبيل المثال، يمكنك تقديم طلب لتقديم طلب إلى واجهة برمجة تطبيقات المنطقة الزمنية:

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

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

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 الأساسية ويتم التعامل معه وفقًا لذلك. ولتجنُّب ذلك، عليك التأكّد من عدم مزامنة طلبات البيانات من واجهة برمجة التطبيقات بين البرامج.

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

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

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

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

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

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

توفّر خدمات الويب في "خرائط 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>
    
Path with أحرف البدل
تعبير XPath:  "/WebServiceResponse//location"
الاختيار:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
مسار مع Predicate
تعبير 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");
    }
  }
}