سرویسهای وب «پلاتفرم Google Maps» مجموعهای از میاناهای HTTP به سرویسهای Google است که دادههای جغرافیایی را برای برنامههای نقشه شما ارائه میدهد.
این راهنما برخیاز روالهای مطلوب رایج را که برای راهاندازی درخواستهای سرویس وب و پردازش پاسخهای سرویس مفید هستند شرح میدهد. برای دریافت مستندات کامل Geocoding API، به راهنمای توسعهدهنده مراجعه کنید.
سرویس وب چیست؟
سرویسهای وب «پلاتفرم Google Maps» میانایی برای درخواست دادههای Maps API از سرویسهای خارجی و استفاده از دادهها در برنامههای Maps شما است. این سرویسها طبق محدودیتهای پروانه در «شرایط خدمات پلاتفرم Google Maps» طراحی شدهاند تا همراه با نقشه استفاده شوند.
سرویسهای وب Maps APIs از درخواستهای HTTP(S) به نشانیهای وب خاص استفاده میکنند و پارامترهای نشانی وب و/یا دادههای POST با قالب JSON را بهعنوان آرگومان به سرویسها ارسال میکنند. بهطور کلی، این سرویسها دادهها را در بدنه پاسخ بهصورت JSON یا XML برای تجزیه و/یا پردازش توسط برنامه شما برمیگردانند.
یک درخواست Geocoding API معمولاً به شکل زیر است:
https://maps.googleapis.com/maps/api/geocode/output?parameters
که output نشاندهنده قالب پاسخ است (معمولاً
json یا xml).
توجه: همه برنامههای «میانای برنامهسازی کاربردی» Geocoding به اصالتسنجی نیاز دارند. درباره اعتبارنامههای اصالتسنجی بیشتر بدانید.
دسترسی 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 |
تبدیل نشانی وبی که از درونداد کاربر دریافت میکنید گاهی اوقات دشوار است. برای مثال، کاربر ممکن است نشانی را بهصورت «5th&Main St.» وارد کند. بهطورکلی، باید نشانی وب خود را از بخشهای آن بسازید و هر ورودی کاربر را بهعنوان نویسههای تحتاللفظی درنظر بگیرید.
علاوهبراین، نشانیهای وب برای همه سرویسهای وب Google Maps Platform و میاناهای برنامهسازی کاربردی وب ایستا به ۱۶۳۸۴ نویسه محدود است. برای اکثر سرویسها، این حد نویسه بهندرت نزدیک میشود. بااینحال، توجه داشته باشید که برخیاز سرویسها چندین پارامتر دارند که ممکن است منجر به نشانیهای وب طولانی شود.
استفاده مؤدبانه از Google APIs
کارخواههای میانای برنامهسازی کاربردی که طراحی ضعیفی دارند میتوانند بار بیشتری از حد لازم بر اینترنت و سرورهای Google تحمیل کنند. این بخش شامل برخیاز روالهای مطلوب برای مشتریان میاناهای برنامهسازی کاربردی است. رعایت این روالهای مطلوب میتواند به شما کمک کند از مسدود شدن برنامهتان بهدلیل سوءاستفاده ناخواسته از میاناهای برنامهسازی کاربردی جلوگیری کنید.
مدیریت خطاها و تلاشهای مجدد
برای کسب اطلاعات درباره کدهای پاسخ UNKNOWN_ERROR یا OVER_QUERY_LIMIT از
Geocoding API، درباره مدیریت خطاها و تلاشهای مجدد بخوانید.
پسگیری نمایی
در موارد نادر، ممکن است مشکلی در ارائه درخواست شما پیش بیاید؛ ممکن است کد پاسخ 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 باشد و براساس آن رفتار شود. برای اجتناب از این مشکل، باید مطمئن شوید که درخواستهای API بین کارخواهها همگامسازی نشدهاند.
برای مثال، برنامهای را درنظر بگیرید که زمان را در منطقه زمانی فعلی نمایش میدهد. این برنامه احتمالاً زنگ هشداری در سیستمعامل کارخواه تنظیم میکند که آن را در ابتدای دقیقه بیدار میکند تا زمان نمایشدادهشده بهروز شود. برنامه نباید هیچ تماسی با «میانای برنامهسازی کاربردی» بهعنوان بخشی از پردازش مرتبط با آن هشدار برقرار کند.
انجام تماسهای API در پاسخ به زنگ هشداری ثابت بد است زیرا باعث میشود تماسهای API با شروع دقیقه همزمان شوند، حتی بین دستگاههای مختلف، بهجای اینکه بهطور یکنواخت در طول زمان توزیع شوند. برنامهای که طراحی ضعیفی دارد و این کار را انجام میدهد، در ابتدای هر دقیقه، ترافیکی ۶۰ برابر سطح عادی ایجاد میکند.
درعوض، یک طراحی خوب احتمالی این است که زنگ هشدار دومی برای زمانی که بهطور تصادفی انتخاب شده است تنظیم شود. وقتی این زنگ هشدار دوم بهصدا درمیآید، برنامه هر API که نیاز دارد را فرا میخواند و نتایج را ذخیره میکند. وقتی برنامه میخواهد نمایش خود را در ابتدای دقیقه بهروز کند، از نتایج ذخیرهشده قبلی استفاده میکند و دوباره API را فراخوانی نمیکند. با این رویکرد، تماسهای میانای برنامهسازی کاربردی بهطور یکنواخت درطول زمان توزیع میشوند. علاوهبراین، فراخوانهای API هنگام بهروزرسانی نمایشگر، پردازش را بهتأخیر نمیاندازند.
علاوهبر شروع دقیقه، زمانهای همگامسازی رایج دیگری که باید مراقب باشید هدف قرار ندهید عبارتاند از شروع ساعت و شروع هر روز در نیمهشب.
درحال پردازش پاسخها
این بخش نحوه استخراج پویای این مقادیر از پاسخهای سرویس وب را توضیح میدهد.
خدمات وب Google Maps پاسخهایی ارائه میدهد که درک آنها آسان است، اما دقیقاً کاربرپسند نیستند. هنگام اجرای پُرسمان، بهجای نمایش مجموعهای از دادهها، احتمالاً میخواهید چند مقدار خاص را استخراج کنید. بهطورکلی، میخواهید پاسخهای سرویس وب را تجزیه کنید و فقط مقادیر موردعلاقهتان را استخراج کنید.
طرح تجزیه مورداستفاده شما بستگی به این دارد که آیا برونداد را در XML یا JSON برمیگردانید. پاسخهای JSON، که درحالحاضر بهشکل اشیاء جاوا اسکریپت هستند، ممکن است در خود جاوا اسکریپت در سمت کارخواه پردازش شوند. پاسخهای XML باید بااستفاده از پردازنده XML و زبان پُرسمان XML پردازش شوند تا عناصر موجود در قالب XML را آدرسدهی کنند. در مثالهای زیر از XPath استفاده میکنیم، زیرا معمولاً در کتابخانههای پردازش XML پشتیبانی میشود.
پردازش XML با XPath
XML یک قالب اطلاعات ساختاریافته نسبتاً بالغ است که برای
تبادل داده استفاده میشود. اگرچه XML بهاندازه JSON سبک نیست،
اما پشتیبانی زبانی بیشتر و ابزارهای قویتری ارائه میدهد. برای مثال، کد پردازش XML در جاوا در
بستههای 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"); } } }