Praktik Terbaik Menggunakan Layanan Web Distance Matrix API

Layanan web Google Maps Platform adalah kumpulan antarmuka HTTP ke Google layanan yang menyediakan data geografis untuk aplikasi peta Anda.

Panduan ini menjelaskan beberapa praktik umum yang berguna untuk menyiapkan layanan web permintaan dan memproses respons layanan. Lihat panduan developer untuk dokumentasi lengkap Distance Matrix API.

Apa yang dimaksud dengan layanan web?

Layanan web Google Maps Platform adalah antarmuka untuk meminta data Maps API dari layanan eksternal dan menggunakan data dalam aplikasi Maps Anda. Layanan ini dirancang untuk digunakan bersama peta, sesuai dengan Pembatasan Lisensi di Persyaratan Layanan Google Maps Platform.

Layanan web Maps API menggunakan permintaan HTTP(S) ke URL tertentu, dengan meneruskan parameter URL, dan/atau Data POST format JSON sebagai argumen ke layanan. Biasanya, layanan ini mengembalikan data di isi respons sebagai JSON atau XML untuk mengurai dan/atau pemrosesan oleh aplikasi Anda.

Permintaan Distance Matrix API umumnya adalah formulir berikut:

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

dengan output menunjukkan format respons (biasanya json atau xml).

Catatan: Semua aplikasi Distance Matrix API memerlukan autentikasi. Dapatkan informasi selengkapnya tentang kredensial autentikasi.

Akses SSL/TLS

HTTPS diperlukan untuk semua permintaan Google Maps Platform yang menggunakan kunci API atau berisi pengguna layanan otomatis dan data skalabel. Permintaan yang dibuat melalui HTTP yang berisi data sensitif dapat ditolak.

Membuat URL yang valid

Anda mungkin menganggap URL yang "valid" sudah jelas, tetapi kenyataannya tidak demikian. URL yang dimasukkan dalam kolom URL di browser, sebagai contoh, dapat berisi karakter khusus (misalnya "上海+中國"); browser harus menerjemahkan karakter tersebut secara internal ke dalam encoding yang berbeda sebelum melakukan transmisi. Dengan token yang sama, setiap kode yang menghasilkan atau menerima input UTF-8 dapat memperlakukan URL berisi karakter UTF-8 sebagai "valid", tetapi juga perlu menerjemahkan karakter tersebut sebelum mengirimnya ke server web. Proses ini disebut encoding URL atau encoding persen.

Karakter khusus

Karakter khusus harus diterjemahkan karena semua URL harus sesuai dengan sintaksis yang ditentukan oleh spesifikasi Uniform Resource Identifier (URI). Dengan demikian, URL hanya boleh berisi sebagian karakter ASCII khusus: simbol alfanumerik yang sudah umum, dan beberapa karakter dengan fungsi khusus untuk digunakan sebagai karakter kontrol dalam URL. Tabel ini merangkum karakter tersebut:

Ringkasan Karakter URL yang Valid
KumpulankarakterPenggunaan URL
Alfanumerik 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 String teks, penggunaan skema (http), port (8080), dll.
Tanpa fungsi khusus - _ . ~ String teks
Dengan fungsi khusus ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Karakter kontrol dan/atau String Teks

Saat membuat URL yang valid, Anda harus memastikan bahwa URL tersebut hanya berisi karakter yang ditampilkan di tabel sementara. Penyesuaian URL untuk menggunakan kumpulan karakter ini biasanya menyebabkan dua masalah, yaitu masalah penghilangan dan masalah penggantian:

  • Karakter yang ingin Anda tangani tidak termasuk dalam kumpulan karakter di atas. Misalnya, karakter dalam bahasa asing seperti 上海+中國 harus dienkode menggunakan karakter di atas. Menurut aturan umum, spasi (yang tidak diizinkan dalam URL) sering kali juga dinyatakan menggunakan karakter plus '+'.
  • Karakter yang ada dalam kumpulan di atas merupakan karakter dengan fungsi khusus, tetapi harus digunakan secara literal. Misalnya, ? digunakan dalam URL untuk menunjukkan awal dari string kueri; jika Anda ingin menggunakan string "? and the Mysterians", Anda harus mengenkode karakter '?'.

Semua karakter yang akan dienkode ke URL dienkode menggunakan karakter '%' dan nilai heksadesimal dua karakter yang sesuai dengan karakter UTF-8. Misalnya, 上海+中國 di UTF-8 akan dienkode ke URL sebagai %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B. String ? and the Mysterians akan dienkode ke URL sebagai %3F+and+the+Mysterians atau %3F%20and%20the%20Mysterians.

Karakter umum yang memerlukan encoding

Beberapa karakter umum yang harus dienkode adalah:

Karakter tidak aman Nilai yang dienkode
Spasi %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

Mengonversi URL yang Anda terima dari input pengguna terkadang rumit. Misalnya, seorang pengguna dapat memasukkan alamat sebagai "5th&Main St." Biasanya, Anda harus membuat URL Anda dari bagian-bagiannya, memperlakukan setiap input pengguna sebagai karakter literal.

Selain itu, URL dibatasi hingga 16.384 karakter untuk semua layanan web Google Maps Platform dan Static Web API. Untuk sebagian besar layanan, batas karakter ini jarang tercapai. Namun, perhatikan bahwa layanan tertentu memiliki beberapa parameter yang dapat menghasilkan URL panjang.

Penggunaan Moderat Google API

Klien API yang tidak dirancang dengan baik dapat menempatkan lebih banyak beban daripada yang diperlukan di Internet dan Server Google. Bagian ini berisi beberapa praktik terbaik untuk klien API. Mengikuti praktik terbaik ini dapat membantu Anda agar aplikasi Anda tidak diblokir karena penyalahgunaan yang tidak disengaja API.

Backoff Eksponensial

Dalam kasus yang jarang terjadi, mungkin terjadi error saat melayani permintaan Anda; Anda mungkin menerima HTTP 4XX atau 5XX kode respons, atau koneksi TCP mungkin gagal di antara klien Anda dan jaringan server tertentu. Sering kali ada gunanya mencoba kembali permintaan sebagai permintaan tindak lanjut mungkin berhasil jika permintaan asli gagal. Namun, penting untuk tidak hanya melakukan loop berulang kali ke server Google. Perilaku pengulangan ini dapat membebani jaringan antara klien Anda dan Google yang menyebabkan masalah bagi banyak pihak.

Pendekatan terbaik adalah mencoba ulang dengan meningkatkan waktu tunda antar percobaan. Biasanya penundaan meningkat dengan faktor perkalian dengan setiap percobaan, pendekatan yang dikenal sebagai Backoff Eksponensial.

Misalnya, pertimbangkan aplikasi yang ingin membuat permintaan ini untuk Time Zone API:

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

Contoh Python berikut menampilkan cara membuat permintaan dengan backoff eksponensial:

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

Anda juga harus berhati-hati bahwa tidak ada percobaan ulang kode yang lebih tinggi dalam panggilan aplikasi rantai yang mengarah ke permintaan berulang dengan cepat.

Permintaan yang Disinkronkan

Permintaan yang disinkronkan ke API Google dalam jumlah besar akan terlihat seperti permintaan Serangan Denial of Service (DDoS) pada infrastruktur Google, dan diperlakukan sebagaimana mestinya. Kepada menghindari hal ini, Anda harus memastikan bahwa permintaan API tidak disinkronkan antar klien.

Misalnya, pertimbangkan aplikasi yang menampilkan waktu dalam zona waktu saat ini. Aplikasi ini mungkin akan menyetel alarm pada sistem operasi klien yang membangunkannya pada awal menit sehingga waktu yang ditampilkan dapat diperbarui. Aplikasi harus tidak membuat panggilan API sebagai bagian dari pemrosesan yang terkait dengan alarm tersebut.

Melakukan panggilan API untuk merespons alarm yang sudah diperbaiki adalah hal yang buruk karena mengakibatkan panggilan API menjadi disinkronkan hingga awal menit, bahkan di antara perangkat yang berbeda, alih-alih didistribusikan secara merata seiring waktu. Aplikasi yang didesain dengan buruk yang melakukan hal ini akan menghasilkan lonjakan lalu lintas pada enam puluh kali tingkat normal pada awal setiap menit.

Sebagai gantinya, satu rancangan yang mungkin baik adalah menyetel alarm kedua ke waktu terpilih yang acak. Saat alarm kedua ini terpicu, aplikasi akan memanggil API apa pun yang diperlukannya dan menyimpan hasil pengujian tersebut. Ketika ingin memperbarui tampilannya di awal menit, aplikasi akan menggunakan hasil yang disimpan sebelumnya daripada memanggil API lagi. Dengan pendekatan ini, panggilan API akan tersebar secara merata dari waktu ke waktu. Selanjutnya, panggilan API tidak menunda rendering saat tampilan diperbarui.

Selain waktu mulai menit, waktu sinkronisasi umum lainnya harus berhati-hati tidak menargetkan adalah di awal jam, dan awal setiap hari pada tengah malam.

Memproses Respons

Bagian ini membahas cara mengekstrak nilai-nilai ini secara dinamis dari respons layanan web.

Layanan web Google Maps memberikan respons yang mudah dipahami, tapi tidak mudah digunakan. Saat melakukan kueri, bukan daripada menampilkan satu set data, Anda mungkin ingin mengekstrak beberapa masing-masing. Biasanya, Anda ingin mengurai respons dari web layanan dan hanya ekstrak nilai-nilai yang Anda minati.

Skema penguraian yang Anda gunakan bergantung pada apakah Anda mengembalikan dalam XML atau JSON. Respons JSON, yang sudah dalam bentuk Objek JavaScript, dapat diproses dalam JavaScript itu sendiri pada klien. Respons XML harus diproses menggunakan pemroses XML dan bahasa kueri XML untuk menangani elemen dalam format XML. Kita menggunakan XPath di dalam contoh berikut, seperti yang biasanya didukung dalam pemrosesan XML library.

Memproses XML dengan XPath

XML adalah format informasi terstruktur yang relatif matang dan digunakan untuk pertukaran data. Meskipun tidak ringan seperti JSON, XML memberikan lebih banyak dukungan bahasa dan alat yang lebih tangguh. Kode untuk memproses XML di Java, misalnya, telah disertakan dalam javax.xml paket.

Saat memproses respons XML, Anda harus menggunakan metode untuk memilih {i>node<i} dalam dokumen XML, bukan daripada mengasumsikan elemen berada pada posisi absolut dalam Markup XML. XPath adalah sintaksis bahasa untuk menggambarkan node dan elemen secara unik dalam dokumen XML. Ekspresi XPath memungkinkan Anda mengidentifikasi konten tertentu dalam dokumen respons XML.

Ekspresi XPath

Pemahaman tentang XPath berkontribusi besar terhadap pengembangan skema penguraian yang tangguh. Bagian ini akan berfokus pada bagaimana elemen dalam dokumen XML ditangani dengan XPath, memungkinkan Anda untuk menangani beberapa elemen dan membangun kueri yang kompleks.

XPath menggunakan ekspresi untuk memilih elemen dalam XML dokumen, menggunakan sintaks yang mirip dengan yang digunakan untuk jalur direktori. Ekspresi ini mengidentifikasi elemen dalam dokumen XML yang merupakan pohon hierarki yang serupa dengan DOM. Umumnya, ekspresi XPath serakah, menunjukkan bahwa ekspresi tersebut akan cocok dengan semua node yang cocok dengan kriteria yang diberikan.

Kita akan menggunakan XML abstrak berikut untuk menggambarkan contoh:

<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>

Pilihan Simpul dalam Ekspresi

Pilihan XPath memilih node. Node root mencakup keseluruhan dokumen. Anda memilih node ini menggunakan ekspresi khusus "/". Perhatikan bahwa root {i>node<i} bukan {i>node<i} tingkat atas dari dokumen XML Anda; sebenarnya, elemen ini berada satu tingkat di atas elemen tingkat atas ini dan mencakup anotasi.

Node elemen mewakili berbagai elemen dalam XML struktur dokumen. Elemen <WebServiceResponse>, misalnya, mewakili elemen tingkat atas yang dikembalikan dalam contoh layanan di atas. Anda memilih setiap {i>node<i} melalui jalur absolut atau relatif, yang ditunjukkan dengan ada atau tidak adanya "/" terdepan karakter.

  • Jalur absolut: "/WebServiceResponse/result" ekspresi memilih semua <result> node yang adalah turunan dari <WebServiceResponse> {i>node<i}. (Perhatikan bahwa kedua elemen ini berlangsung berasal dari {i>root<i} node "/".)
  • Jalur relatif dari konteks saat ini: ekspresi "result" akan cocok dengan <result> elemen dalam konteks saat ini. Umumnya, Anda tidak Anda harus memahami konteks, karena Anda biasanya memproses email hasil layanan melalui ekspresi tunggal.

Salah satu ekspresi ini dapat ditambahkan melalui penambahan jalur karakter pengganti, yang ditunjukkan dengan garis miring ganda ("//"). Karakter pengganti ini menunjukkan bahwa nol atau beberapa elemen mungkin cocok di jalur intervensi. Ekspresi XPath "//formatted_address", misalnya, akan cocok dengan semua simpul dari nama itu dalam dokumen saat ini. Ekspresi //viewport//lat akan cocok dengan semua Elemen <lat> yang dapat merekam aktivitas <viewport> sebagai orang tua.

Secara default, ekspresi XPath cocok dengan semua elemen. Anda dapat membatasi agar cocok dengan elemen tertentu dengan memberikan predikat, yang diapit tanda kurung siku ([]). XPath ekspresi "/GeocodeResponse/result[2] selalu menampilkan hasil kedua, misalnya.

Tipe Ekspresi
Simpul akar
Ekspresi XPath: "/"
Pilihan:
    <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>
    
Jalur Absolut
Ekspresi XPath: "/WebServiceResponse/result"
Pilihan:
    <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>
    
Jalur dengan Karakter Pengganti
Ekspresi XPath: "/WebServiceResponse//location"
Pilihan:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Jalur dengan Predikat
Ekspresi XPath: "/WebServiceResponse/result[2]/message"
Pilihan:
    <message>The secret message</message>
    
Semua turunan langsung dari result pertama
Ekspresi XPath: "/WebServiceResponse/result[1]/*"
Pilihan:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
name dari result yang teks type-nya adalah "sample".
Ekspresi XPath: "/WebServiceResponse/result[type/text()='sample']/name"
Pilihan:
    Sample XML
    

Penting untuk dicatat bahwa ketika memilih elemen, Anda memilih {i>node<i}, tidak hanya pada teks di dalam objek tersebut. Umumnya, Anda ingin mengulangi semua {i>node<i} yang cocok dan mengekstrak teksnya. Anda juga dapat mencocokkan node teks secara langsung; lihat Text Nodes di bawah.

Perhatikan bahwa XPath juga mendukung simpul atribut; namun, semua layanan web Google Maps menyajikan elemen tanpa atribut, jadi pencocokan atribut tidak perlu.

Pemilihan Teks dalam Ekspresi

Teks dalam dokumen XML ditentukan dalam ekspresi XPath melalui operator node teks. Operator ini "text()" menunjukkan ekstraksi teks dari simpul yang ditunjukkan. Misalnya, ekspresi XPath "//formatted_address/text()" oleh tampilkan semua teks dalam <formatted_address> yang kurang penting.

Tipe Ekspresi
Semua simpul teks (termasuk spasi)
Ekspresi XPath: "//text()"
Pilihan:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Pemilihan Teks
Ekspresi XPath: "/WebServiceRequest/result[2]/message/text()"
Pilihan:
    The secret message
    
Pilihan Sesuai Konteks
Ekspresi XPath: "/WebServiceRequest/result[type/text() = 'sample']/name/text()"
Pilihan:
    Sample XML
    

Atau, Anda bisa mengevaluasi ekspresi dan mengembalikan set {i>node<i} dan kemudian melakukan iterasi pada "set {i>node<i}," mengekstrak teks dari setiap {i>node<i}. Kami menggunakan pendekatan ini dalam contoh di bawah.

Untuk informasi selengkapnya tentang XPath, lihat Spesifikasi W3C XPath.

Mengevaluasi XPath di Java

Java memiliki dukungan luas untuk mengurai XML dan menggunakan ekspresi XPath dalam paket javax.xml.xpath.*. Karena itu, kode contoh di bagian ini menggunakan Java untuk mengilustrasikan cara menangani XML dan mengurai data dari respons layanan XML.

Untuk menggunakan XPath dalam kode Java, Anda harus membuat instance terlebih dahulu instance XPathFactory dan memanggil newXPath() di factory tersebut untuk membuat objek XPath . Objek ini kemudian dapat memproses XML yang diteruskan dan XPath menggunakan metode evaluate().

Saat mengevaluasi ekspresi XPath, pastikan Anda melakukan iterasi pada setiap kemungkinan "kumpulan node" yang mungkin ditampilkan. Karena layanan hasil dikembalikan sebagai simpul DOM dalam kode Java, Anda harus menangkap banyak nilai tersebut dalam objek NodeList dan ulangi objek tersebut untuk mengekstrak teks atau nilai apa pun dari node.

Kode berikut mengilustrasikan cara membuat XPath , beri XML dan ekspresi XPath, lalu evaluasi ekspresi untuk mencetak konten yang relevan.

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