بهترین روش ها با استفاده از خدمات وب API مدیریت نقشه

سرویس‌های وب پلتفرم نقشه‌های گوگل مجموعه‌ای از رابط‌های HTTP به سرویس‌های گوگل هستند که داده‌های جغرافیایی را برای برنامه‌های نقشه شما فراهم می‌کنند.

این راهنما برخی از شیوه‌های رایج مفید برای تنظیم درخواست‌های وب سرویس شما و پردازش پاسخ‌های سرویس را شرح می‌دهد. برای مشاهده مستندات کامل API مدیریت نقشه، به راهنمای توسعه‌دهنده مراجعه کنید.

وب سرویس چیست؟

سرویس‌های وب پلتفرم نقشه‌های گوگل رابطی برای درخواست داده‌های API نقشه‌ها از سرویس‌های خارجی و استفاده از داده‌ها در برنامه‌های نقشه شما هستند. این سرویس‌ها برای استفاده در ارتباط با یک نقشه، مطابق با محدودیت‌های مجوز در شرایط خدمات پلتفرم نقشه‌های گوگل، طراحی شده‌اند.

سرویس‌های وب Maps API از درخواست‌های HTTP(S) به URLهای خاص استفاده می‌کنند و پارامترهای URL و/یا داده‌های POST با فرمت JSON را به عنوان آرگومان به سرویس‌ها ارسال می‌کنند. عموماً، این سرویس‌ها داده‌ها را در بدنه پاسخ به صورت JSON برای تجزیه و/یا پردازش توسط برنامه شما برمی‌گردانند.

مثال زیر یک درخواست REST GET به متد Map Configs در لیست را نشان می‌دهد:

https://mapmanagement.googleapis.com/v2beta/projects/PROJECT_NUMBER_OR_ID/mapConfigs

درخواست خود را با استفاده از توکن OAuth در Authorization header وارد کنید.

دسترسی SSL/TLS

HTTPS برای تمام درخواست‌های پلتفرم نقشه‌های گوگل که از کلیدهای API استفاده می‌کنند یا حاوی داده‌های کاربر هستند، الزامی است. درخواست‌های ارسالی از طریق HTTP که حاوی داده‌های حساس هستند، ممکن است رد شوند.

ساخت یک URL معتبر

ممکن است فکر کنید که یک URL «معتبر» بدیهی است، اما کاملاً اینطور نیست. برای مثال، یک URL که در نوار آدرس مرورگر وارد می‌شود، ممکن است حاوی کاراکترهای خاص باشد (مثلاً "上海+中國" )؛ مرورگر باید قبل از ارسال، آن کاراکترها را به صورت داخلی به یک کدگذاری متفاوت ترجمه کند. به همین ترتیب، هر کدی که ورودی UTF-8 را تولید یا می‌پذیرد، ممکن است URLهایی با کاراکترهای UTF-8 را به عنوان "معتبر" در نظر بگیرد، اما قبل از ارسال آنها به یک سرور وب، باید آن کاراکترها را نیز ترجمه کند. این فرآیند کدگذاری URL یا کدگذاری درصد نامیده می‌شود.

شخصیت‌های ویژه

ما نیاز به ترجمه کاراکترهای ویژه داریم زیرا همه URLها باید با سینتکس مشخص شده توسط مشخصات شناسه منبع یکسان (URI) مطابقت داشته باشند. در واقع، این بدان معناست که URLها باید فقط شامل یک زیرمجموعه خاص از کاراکترهای ASCII باشند: نمادهای الفبایی-عددی آشنا و برخی کاراکترهای رزرو شده برای استفاده به عنوان کاراکترهای کنترلی در URLها. این جدول این کاراکترها را خلاصه می‌کند:

خلاصه‌ای از کاراکترهای معتبر URL
تنظیم شخصیت‌ها استفاده از آدرس اینترنتی (URL)
الفبایی-عددی abcdefghijklm nopqrstuvwxyz ABCDEFGHIJKLM NOPQRSTUVWXYZ 0 1 2 3 4 5 6 7 8 9 رشته‌های متنی، استفاده از طرح ( 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 رمزگذاری URL می‌شوند. رشته ? and the Mysterians به صورت %3F+and+the+Mysterians یا %3F%20and%20the%20Mysterians رمزگذاری URL می‌شوند.

کاراکترهای رایجی که نیاز به کدگذاری دارند

برخی از کاراکترهای رایج که باید رمزگذاری شوند عبارتند از:

شخصیت ناامن مقدار کدگذاری شده
فضا %20
« %22
< %3C
> %3E
# %23
% %25
| %7C

تبدیل URL ای که از ورودی کاربر دریافت می‌کنید، گاهی اوقات دشوار است. برای مثال، ممکن است کاربر آدرسی به صورت "خیابان پنجم و اصلی" وارد کند. به طور کلی، شما باید URL خود را از بخش‌های آن بسازید و هر ورودی کاربر را به عنوان کاراکترهای تحت‌اللفظی در نظر بگیرید.

علاوه بر این، URL ها برای همه سرویس‌های وب پلتفرم نقشه‌های گوگل و API های وب استاتیک به ۱۶۳۸۴ کاراکتر محدود می‌شوند. برای اکثر سرویس‌ها، این محدودیت کاراکتر به ندرت رعایت می‌شود. با این حال، توجه داشته باشید که برخی سرویس‌ها پارامترهای متعددی دارند که ممکن است منجر به URL های طولانی شوند.

استفاده مودبانه از API های گوگل

کلاینت‌های API با طراحی ضعیف می‌توانند بار بیش از حد لازم را هم بر روی اینترنت و هم بر روی سرورهای گوگل اعمال کنند. این بخش شامل برخی از بهترین شیوه‌ها برای کلاینت‌های API است. پیروی از این بهترین شیوه‌ها می‌تواند به شما کمک کند تا از مسدود شدن برنامه خود به دلیل سوءاستفاده غیرعمدی از APIها جلوگیری کنید.

عقب‌نشینی نمایی

در موارد نادر، ممکن است در ارائه درخواست شما مشکلی پیش بیاید؛ ممکن است کد پاسخ HTTP با کد 4XX یا 5XX دریافت کنید، یا اتصال TCP بین کلاینت شما و سرور گوگل به سادگی قطع شود. اغلب ارزش دارد که درخواست را دوباره امتحان کنید زیرا ممکن است درخواست بعدی در حالی که درخواست اصلی ناموفق بوده، موفق شود. با این حال، مهم است که درخواست‌های مکرر به سرورهای گوگل را به سادگی در حلقه تکرار قرار ندهید. این رفتار حلقه‌ای می‌تواند شبکه بین کلاینت شما و گوگل را بیش از حد بارگذاری کند و برای بسیاری از طرفین مشکل ایجاد کند.

یک رویکرد بهتر، تلاش مجدد با افزایش تأخیر بین تلاش‌ها است. معمولاً تأخیر با هر تلاش به میزان یک ضریب افزایش می‌یابد، رویکردی که به عنوان Exponential Backoff شناخته می‌شود.

برای مثال، برنامه‌ای را در نظر بگیرید که می‌خواهد این درخواست را به API منطقه زمانی ارسال کند:

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

مثال پایتون زیر نحوه‌ی ارسال درخواست با backoff نمایی را نشان می‌دهد:

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}")

همچنین باید مراقب باشید که کد تلاش مجدد در زنجیره فراخوانی برنامه بالاتر نباشد که منجر به درخواست‌های مکرر و پشت سر هم شود.

درخواست‌های همگام‌سازی شده

تعداد زیادی از درخواست‌های هماهنگ‌شده به APIهای گوگل می‌توانند مانند حمله‌ی انکار سرویس توزیع‌شده (DDoS) به زیرساخت گوگل به نظر برسند و بر این اساس با آنها برخورد شود. برای جلوگیری از این امر، باید مطمئن شوید که درخواست‌های API بین کلاینت‌ها هماهنگ نمی‌شوند.

برای مثال، برنامه‌ای را در نظر بگیرید که زمان را در منطقه زمانی فعلی نمایش می‌دهد. این برنامه احتمالاً در سیستم عامل کلاینت، آلارمی تنظیم می‌کند که آن را در شروع دقیقه بیدار می‌کند تا زمان نمایش داده شده به‌روزرسانی شود. برنامه نباید هیچ فراخوانی API را به عنوان بخشی از پردازش مرتبط با آن آلارم انجام دهد.

انجام فراخوانی‌های API در پاسخ به یک آلارم ثابت، کار بدی است، زیرا منجر به همگام‌سازی فراخوانی‌های API با شروع دقیقه، حتی بین دستگاه‌های مختلف، به جای توزیع یکنواخت در طول زمان می‌شود. یک برنامه با طراحی ضعیف که این کار را انجام می‌دهد، باعث افزایش ترافیک به میزان شصت برابر سطح عادی در شروع هر دقیقه می‌شود.

در عوض، یک طرح خوب ممکن این است که یک زنگ هشدار دوم روی یک زمان تصادفی انتخاب شده تنظیم شود. وقتی این زنگ هشدار دوم فعال می‌شود، برنامه هر API مورد نیاز خود را فراخوانی می‌کند و نتایج را ذخیره می‌کند. وقتی برنامه می‌خواهد نمایش خود را در ابتدای دقیقه به‌روزرسانی کند، به جای فراخوانی مجدد API، از نتایج ذخیره شده قبلی استفاده می‌کند. با این رویکرد، فراخوانی‌های API به طور مساوی در طول زمان پخش می‌شوند. علاوه بر این، فراخوانی‌های API هنگام به‌روزرسانی نمایش، رندر را به تأخیر نمی‌اندازند.

گذشته از شروع دقیقه، سایر زمان‌های همگام‌سازی رایج که باید مراقب باشید آنها را هدف قرار ندهید ، شروع ساعت و شروع هر روز در نیمه‌شب هستند.

پردازش پاسخ‌ها

این بخش به چگونگی استخراج پویای این مقادیر از پاسخ‌های وب سرویس می‌پردازد.

سرویس‌های وب نقشه‌های گوگل پاسخ‌هایی ارائه می‌دهند که به راحتی قابل فهم هستند، اما دقیقاً کاربرپسند نیستند. هنگام انجام یک پرس‌وجو، به جای نمایش مجموعه‌ای از داده‌ها، احتمالاً می‌خواهید چند مقدار خاص را استخراج کنید. به طور کلی، شما می‌خواهید پاسخ‌ها را از سرویس وب تجزیه کنید و فقط مقادیری را که برای شما جالب هستند استخراج کنید.

طرح تجزیه‌ای که استفاده می‌کنید بستگی به این دارد که آیا خروجی را به صورت JSON برمی‌گردانید یا خیر. پاسخ‌های JSON، که از قبل به شکل اشیاء جاوااسکریپت هستند، ممکن است در خود جاوااسکریپت روی کلاینت پردازش شوند.