سرویسهای وب «پلاتفرم Google Maps» مجموعهای از میاناهای HTTP به سرویسهای Google است که دادههای جغرافیایی را برای برنامههای نقشه شما ارائه میدهد.
این راهنما برخیاز روالهای رایج را که برای راهاندازی درخواستهای سرویس وب و پردازش پاسخهای سرویس مفید هستند شرح میدهد. برای دریافت مستندات کامل Directions API (قدیمی)، به راهنمای توسعهدهنده مراجعه کنید.
سرویس وب چیست؟
خدمات وب «پلاتفرم Google Maps» میانایی برای درخواست دادههای Maps API از سرویسهای خارجی و استفاده از دادهها در برنامههای Maps شما است. این سرویسها طراحی شدهاند تا مطابق با محدودیتهای پروانه در «شرایط خدمات پلاتفرم Google Maps»، همراه با نقشه استفاده شوند.
سرویسهای وب Maps APIs از درخواستهای HTTP(S) به نشانیهای وب خاص استفاده میکنند و پارامترهای نشانی وب و/یا دادههای POST با قالب JSON را بهعنوان آرگومان به سرویسها ارسال میکنند. بهطورکلی، این سرویسها دادهها را در بدنه پاسخ بهصورت JSON یا XML برای تجزیه و/یا پردازش توسط برنامه شما برمیگردانند.
درخواست معمول Directions API (قدیمی) معمولاً بهشکل زیر است:
https://maps.googleapis.com/maps/api/directions/output?parameters
که output نشاندهنده قالب پاسخ است (معمولاً
json یا xml).
توجه: همه برنامههای Directions API (قدیمی) به اصالتسنجی نیاز دارند. درباره اعتبارنامههای اصالتسنجی بیشتر بدانید.
دسترسی SSL/TLS
برای همه درخواستهای «پلاتفرم Google Maps» که از کلیدهای API استفاده میکنند یا حاوی دادههای کاربر هستند، HTTPS الزامی است. درخواستهای ارائهشده ازطریق HTTP که حاوی دادههای حساس باشند ممکن است رد شوند.
درحال ساختن نشانی وب معتبر
ممکن است فکر کنید که نشانی وب «معتبر» واضح است، اما
اینطور نیست. برای مثال، نشانی وبی که در نوار نشانی مرورگر وارد میشود ممکن است حاوی نویسههای خاص (مثل "上海+中國") باشد؛ مرورگر باید قبلاز انتقال، این نویسهها را بهطور داخلی به کدبندی دیگری ترجمه کند.
بههمین ترتیب، هر کدی که ورودی UTF-8 تولید یا دریافت میکند
ممکن است نشانیهای وب دارای نویسههای UTF-8 را «معتبر» درنظر بگیرد، اما همچنین باید
این نویسهها را قبلاز ارسال به سرور وب ترجمه کند.
این فرایند
کدبندی نشانی وب یا کدبندی درصدی نامیده میشود.
نویسههای خاص
باید نویسههای خاص را ترجمه کنیم زیرا همه نشانیهای وب باید با نحو مشخصشده در مشخصات شناسه منبع یکسان (URI) مطابقت داشته باشند. درواقع، این یعنی نشانیهای وب باید فقط شامل زیرمجموعه خاصی از نویسههای ASCII باشند: نمادهای آلفانومریک آشنا، و برخی نویسههای رزروشده برای استفاده بهعنوان نویسههای کنترل در نشانیهای وب. این جدول این نویسهها را خلاصه میکند:
| بهصف | نویسهها | استفاده از نشانی وب |
|---|---|---|
| الفباعددی | a b 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 K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 | رشتههای نوشتاری، استفاده از طرح (http)، درگاه (8080)، و غیره. |
| رزرو نشده است | - _ . ~ | رشتههای نوشتاری |
| رزروشده | ! * ' ( ) ; : @ & = + $ , / ? % # [ ] | نویسههای کنترلی و/یا رشتههای نوشتاری |
هنگام ساختن نشانی وب معتبر، باید مطمئن شوید که فقط حاوی نویسههای نشاندادهشده در جدول باشد. منطبق کردن نشانی وب برای استفاده از این مجموعه نویسهها معمولاً به دو مشکل منجر میشود، یکی حذف و دیگری جایگزینی:
- نویسههایی که میخواهید مدیریت کنید خارج از مجموعه بالا قرار دارند. برای مثال، نویسههای زبانهای خارجی
مانند
上海+中國باید بااستفاده از نویسههای بالا کدگذاری شوند. طبق قراردادهای رایج، فاصلهها (که در نشانیهای وب مجاز نیستند) اغلب بااستفاده از نویسه بهعلاوه'+'نیز نشان داده میشوند. - نویسههایی در مجموعه بالا بهعنوان نویسههای رزروشده وجود دارند،
اما باید بهصورت تحتاللفظی استفاده شوند.
برای مثال،
?در نشانیهای وب برای نشان دادن شروع رشته پُرسمان استفاده میشود؛ اگر بخواهید از رشته «? and the Mysterions» استفاده کنید، باید نویسه'?'را کدبندی کنید.
همه نویسههایی که باید کدبندی URL شوند، بااستفاده از نویسه '%' و مقدار هگز دو نویسهای مربوط به نویسه UTF-8 آنها کدبندی میشوند. برای مثال،
上海+中國 در UTF-8 بهصورت
%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 |
تبدیل نشانی وبی که از ورودی کاربر دریافت میکنید گاهی اوقات دشوار است. برای مثال، ممکن است کاربر نشانی را بهصورت «خیابان پنجم و اصلی» وارد کند. بهطور کلی، باید نشانی وب را از بخشهای آن بسازید و هر ورودی کاربر را بهعنوان نویسههای تحتاللفظی درنظر بگیرید.
علاوهبراین، نشانیهای وب برای همه سرویسهای وب Google Maps Platform و میاناهای برنامهسازی کاربردی وب ایستا به ۱۶۳۸۴ نویسه محدود است. برای اکثر سرویسها، این حد نویسه بهندرت نزدیک میشود. بااینحال، توجه داشته باشید که برخیاز سرویسها چندین پارامتر دارند که ممکن است منجر به نشانیهای وب طولانی شود.
استفاده مؤدبانه از 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×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 باشد و براساس آن رفتار شود. برای اجتناب از این امر، باید مطمئن شوید که درخواستهای API بین کارخواهها همگامسازی نمیشوند.
برای مثال، برنامهای را درنظر بگیرید که زمان را در منطقه زمانی فعلی نمایش میدهد. این برنامه احتمالاً زنگ هشداری در سیستمعامل کارخواه تنظیم میکند که آن را در ابتدای دقیقه بیدار میکند تا زمان نمایشدادهشده بهروز شود. برنامه نباید هیچگونه فراخوانی میانای برنامهسازی کاربردی را بهعنوان بخشی از پردازش مرتبط با آن هشدار انجام دهد.
برقراری تماسهای API در پاسخ به زنگ هشدار ثابت خوب نیست زیرا باعث میشود تماسهای API با شروع دقیقه همگامسازی شوند، حتی بین دستگاههای مختلف، بهجای اینکه بهطور یکنواخت درطول زمان توزیع شوند. برنامهای که طراحی ضعیفی داشته باشد و این کار را انجام دهد، در ابتدای هر دقیقه، افزایش ناگهانی ترافیک تا شصت برابر سطح عادی ایجاد میکند.
درعوض، یکی از طراحیهای خوب ممکن است این باشد که زنگ هشدار دومی را برای زمان تصادفی تنظیم کنید. وقتی این زنگ هشدار دوم بهصدا درمیآید، برنامه هر API که نیاز دارد را فرا میخواند و نتایج را ذخیره میکند. وقتی برنامه میخواهد نمایشگرش را در ابتدای دقیقه بهروز کند، از نتایج قبلاً ذخیرهشده استفاده میکند و دوباره با API تماس نمیگیرد. با این رویکرد، تماسهای میانای برنامهسازی کاربردی بهطور یکنواخت درطول زمان توزیع میشوند. علاوهبراین، فراخوانهای میانای برنامهسازی کاربردی هنگام بهروزرسانی نمایشگر، پردازش را بهتأخیر نمیاندازند.
علاوهبر شروع دقیقه، زمانهای همگامسازی رایج دیگری که باید مراقب باشید هدف قرار ندهید عبارتاند از شروع ساعت و شروع هر روز در نیمهشب.
درحال پردازش پاسخها
این بخش نحوه استخراج پویای این مقادیر از پاسخهای سرویس وب را توضیح میدهد.
سرویسهای وب Google Maps پاسخهایی ارائه میدهند که درک آنها آسان است، اما دقیقاً کاربرپسند نیستند. هنگام اجرای پُرسمان، بهجای نمایش مجموعهای از دادهها، احتمالاً میخواهید چند مقدار خاص را استخراج کنید. بهطورکلی، میخواهید پاسخهای سرویس وب را تجزیه کنید و فقط مقادیر موردعلاقهتان را استخراج کنید.
طرح تجزیه مورداستفاده شما بستگی به این دارد که آیا برونداد را در XML یا JSON برمیگردانید. پاسخهای JSON، که درحالحاضر بهشکل اشیاء جاوا اسکریپت هستند، ممکن است در خود جاوا اسکریپت در سمت کارخواه پردازش شوند. پاسخهای XML باید بااستفاده از پردازنده XML و زبان پُرسمان XML پردازش شوند تا عناصر موجود در قالب XML را آدرسدهی کنند. ما از XPath در نمونههای زیر استفاده میکنیم، زیرا معمولاً در کتابخانههای پردازش XML پشتیبانی میشود.
پردازش XML با XPath
XML یک قالب اطلاعات ساختاریافته نسبتاً بالغ است که برای
تبادل داده استفاده میشود. اگرچه XML بهاندازه JSON سبک نیست،
اما پشتیبانی زبانی بیشتر و ابزارهای قویتری ارائه میدهد. برای مثال، کد پردازش 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 با همه عناصر مطابقت دارند. میتوانید عبارت را با ارائه یک گزاره که در کروشه ([]) قرار دارد، برای مطابقت با یک عنصر خاص محدود کنید. برای مثال، عبارت XPath «/GeocodeResponse/result[2] همیشه نتیجه دوم را برمیگرداند.
| نوع عبارت | |
|---|---|
| گره ریشه | عبارت 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 Maps عناصر را بدون مشخصه ارائه میدهند، بنابراین تطبیق مشخصهها ضروری نیست.
انتخاب نوشتار در «عبارات»
نوشتار درون سند 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
جاوا پشتیبانی گستردهای از تجزیه 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"); } } }