خدمات الويب في "منصة خرائط Google" هي مجموعة من واجهات HTTP لخدمات Google توفر بيانات جغرافية لتطبيقات الخرائط.
يوضّح هذا الدليل بعض الممارسات الشائعة المفيدة لإعداد طلبات خدمة الويب وطلبات معالجة الطلبات. يمكنك الرجوع إلى دليل مطوّر البرامج للحصول على مستندات كاملة عن واجهة برمجة تطبيقات الاتجاهات.
ما المقصود بخدمة الويب؟
خدمات الويب على "منصة خرائط Google" هي واجهة لطلب بيانات من واجهة برمجة التطبيقات للخرائط من الخدمات الخارجية واستخدام البيانات داخل تطبيقات الخرائط. تم تصميم هذه الخدمات لاستخدامها مع خريطة، وفقًا لقيود الترخيص في بنود خدمة "منصة خرائط Google".
تستخدم خدمات الويب في Maps API طلبات HTTP(S) لعناوين URL محددة وتمرير معلمات عناوين URL و/أو بيانات تنسيق POST بتنسيق JSON كوسيطات للخدمات. بشكل عام، تعرض هذه الخدمات البيانات في طلب HTTP(S) إما بتنسيق JSON أو XML لتحليلها و/أو معالجتها بواسطة تطبيقك.
بشكل عام، يكون طلب البيانات من واجهة برمجة التطبيقات Directions النموذجي بشكل عام:
https://maps.googleapis.com/maps/api/directions/output?parameters
حيث يشير output
إلى تنسيق الاستجابة (عادةً
json
أو xml
).
ملاحظة: تتطلب جميع تطبيقات واجهة برمجة تطبيقات الاتجاهات الحصول على مصادقة. تعرَّف على المزيد من المعلومات عن بيانات اعتماد المصادقة.
الوصول إلى طبقة المقابس الآمنة (SSL)/طبقة النقل الآمنة (TLS)
يجب استخدام HTTPS لكل طلبات "منصة خرائط Google" التي تستخدم مفاتيح واجهة برمجة التطبيقات أو تتضمّن بيانات المستخدمين. قد يتم رفض الطلبات المقدَّمة عبر HTTP والتي تحتوي على بيانات حساسة.
إنشاء عنوان URL صالح
قد تظن أنّ عنوان URL الخاص بـ " متوفّر; "واضح أنّه يجب أن يكون مفهومًا ذاتيًا, لكن
هذا ليس صحيحًا. على سبيل المثال، قد يحتوي عنوان URL الذي يتم إدخاله في شريط عناوين في أحد المتصفّحات على رموز خاصة (مثل "上海+中國"
)، على المتصفّح ترجمة هذه الأحرف داخليًا إلى ترميز مختلف قبل نقلها.
بالإضافة إلى ذلك، إنّ أي رمز ينشئ أو يقبل إدخال UTF-8
قد يتعامل مع عناوين URL التي تحتوي على أحرف UTF-8 على أنّها &&;;quot;valid" ولكن قد تحتاج أيضًا إلى ترجمة تلك الأحرف قبل إرسالها إلى خادم ويب.
وتسمى هذه العملية
ترميز عنوان URL أو نسبة مئوية.
الأحرف الخاصة
ويجب ترجمة الرموز الخاصة لأنّ جميع عناوين URL تحتاج إلى التوافق مع البنية المحدّدة في مواصفات معرّف الموارد المنتظم (URI). عمليًا، يعني هذا أنّ عناوين URL يجب أن تحتوي على مجموعة فرعية خاصة فقط من أحرف ASCII: وهي رموز أبجدية رقمية مألوفة وبعض الأحرف المحجوزة لاستخدامها كأحرف تحكم ضمن عناوين URL. ويلخّص هذا الجدول الأحرف التالية:
تحديد | الأحرف | استخدام عنوان URL |
---|---|---|
أحرف أبجدية رقمية | أ ب | سلاسل نصية واستخدام المخطّط (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
على النحو التالي: %3F+and+the+Mysterians
أو %3F%20and%20the%20Mysterians
.
الأحرف الشائعة التي تحتاج إلى ترميز
في ما يلي بعض الأحرف الشائعة التي يجب ترميزها:
حرف غير آمن | القيمة المشفَّرة |
---|---|
مفتاح المسافة | %20 |
" | %22 |
< | %3C |
> | %3E |
الرقم | %23 |
نسبة مئوية | %25 |
| | %7C |
قد يصعب أحيانًا تحويل عنوان URL الذي تتلقّاه من المستخدم. على سبيل المثال، قد يُدخل المستخدم عنوانًا بالشكل التالي: "5&&&;&; الشارع الرئيسي&; وبشكل عام، يجب إنشاء عنوان 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×tamp=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 هو تنسيق معلومات منظمة نسبيًا للكبار يُستخدم لتبادل البيانات. ورغم أنّ XML لا يكون خفيفًا مثل تنسيق XML، إلا أنّه يوفّر المزيد من الدعم اللغوي وأدوات أكثر فعالية. ويكون رمز
معالجة XML في Java مثلاً مضمّنًا في
حِزم javax.xml
.
عند معالجة استجابات XML، يجب استخدام لغة طلب بحث مناسبة لاختيار العُقد ضمن مستند XML، بدلاً من افتراض العناصر الموجودة في مواضع مطلقة داخل ترميز XML. وXPath هو بنية لغة لوصف العُقد والعناصر بشكل فريد في مستند XML. تسمح لك تعبيرات XPath بتحديد محتوى معيّن ضمن مستند استجابة XML.
تعبيرات XPath
إنّ الإلمام بموضوع XPath يشكّل عاملاً صعبًا في تحقيق مخطط تحليل فعّال. سيركز هذا القسم على كيفية التعامل مع العناصر ضمن مستند XML باستخدام XPath، ما يسمح لك بمعالجة عناصر متعددة وإنشاء طلبات بحث معقدة.
يستخدم XPath التعبيرات لاختيار عناصر ضمن مستند XML، باستخدام بنية مشابهة لتلك المستخدمة في مسارات الدليل. تحدد هذه التعبيرات العناصر داخل شجرة مستند XML، وهي شجرة هرمية مشابهة لشجرة DOM. وبوجهٍ عام، تتم كتابة تعبيرات 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 "sample;". |
تعبير 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"); } } }