Mesafe Matrisi API'si Web Hizmetlerinin Kullanımıyla İlgili En İyi Uygulamalar

Google Haritalar Platformu web hizmetleri, harita uygulamalarınız için coğrafi veriler sağlayan Google hizmetlerine yönelik bir HTTP arayüzleri koleksiyonudur.

Bu kılavuzda, web hizmeti isteklerinizi ayarlamak ve hizmet yanıtlarını işlemek için faydalı olan bazı yaygın uygulamalar açıklanmaktadır. Mesafe Matrisi API'sinin tüm belgeleri için geliştirici kılavuzunu inceleyin.

Web hizmeti nedir?

Google Haritalar Platformu web hizmetleri, harici hizmetlerden Maps API verileri istemek ve bu verileri Haritalar uygulamalarınızda kullanmak için kullanılan bir arayüzdür. Bu hizmetler, Google Haritalar Platformu Hizmet Şartları'ndaki Lisans Kısıtlamaları uyarınca bir haritayla birlikte kullanılmak üzere tasarlanmıştır.

Haritalar API'leri web hizmetleri, belirli URL'lere yapılan HTTP(S) isteklerini, URL parametrelerini ve/veya JSON biçimli POST verilerini hizmetlere bağımsız değişken olarak iletir. Genel olarak bu hizmetler, verileri uygulamanız tarafından ayrıştırılmak ve/veya işlemek için yanıt gövdesine JSON ya da XML biçiminde döndürür.

Tipik bir Mesafe Matrisi API isteği genellikle aşağıdaki biçimdedir:

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

burada output, yanıt biçimini (genellikle json veya xml) gösterir.

Not: Tüm Mesafe Matrisi API uygulamaları için kimlik doğrulama gerekir. Kimlik doğrulama kimlik bilgileri hakkında daha fazla bilgi edinin.

SSL/TLS Erişimi

HTTPS, API anahtarları kullanan veya kullanıcı verileri içeren tüm Google Haritalar Platformu istekleri için zorunludur. Hassas veriler içeren HTTP üzerinden yapılan istekler reddedilebilir.

Geçerli bir URL oluşturma

"Geçerli" bir URL'nin kendiliğinden görünür olduğunu düşünebilirsiniz, ancak bu doğru değildir. Örneğin, bir tarayıcıdaki adres çubuğuna girilen bir URL, özel karakterler (ör. "上海+中國") içerebilir; tarayıcının bu karakterleri iletilmeden önce dahili olarak farklı bir kodlamaya çevirmesi gerekir. Aynı şekilde, UTF-8 girişlerini oluşturan veya kabul eden tüm kodlar UTF-8 karakterli URL'leri "geçerli" olarak değerlendirebilir ancak bu karakterleri bir web sunucusuna gönderilmeden önce çevirmesi de gerekir. Bu işlem, URL kodlaması veya yüzde kodlaması olarak adlandırılır.

Özel karakterler

Tüm URL'lerin Tek Tip Kaynak Tanımlayıcısı (URI) spesifikasyonunda belirtilen söz dizimine uyması gerektiğinden özel karakterleri çevirmemiz gerekir. Aslında bu, URL'lerin yalnızca özel bir ASCII karakterler alt kümesini içermesi gerektiği anlamına gelir: bilindik alfasayısal simgeler ve URL'lerde kontrol karakterleri olarak kullanılmak üzere ayrılmış bazı karakterler. Bu tabloda şu karakterler özetlenmektedir:

Geçerli URL Karakterlerinin Özeti
AyarlakarakterlerURL kullanımı
Alfanümerik Metin dizeleri, şema kullanımı (http), bağlantı noktası (8080) vb.
Ayrılmamış - _ . ~ Metin dizeleri
Rezervasyon yapıldı ! * ' ( ) ; : @ & = + ₺ , / ? % # [ ] Karakterleri ve/veya Metin Dizelerini kontrol etme

Geçerli bir URL oluştururken, yalnızca Geçerli URL Karakterleri Özeti tablosunda gösterilen karakterleri içerdiğinden emin olmanız gerekir. Bir URL'nin bu karakter kümesini kullanacak şekilde oluşturulması, genellikle biri eksiklik, diğeri değiştirme olmak üzere iki soruna yol açar:

  • İşlemek istediğiniz karakterler yukarıdaki grubun dışında bulunuyor. Örneğin, 上海+中國 gibi yabancı dillerdeki karakterler yukarıdaki karakterler kullanılarak kodlanmalıdır. Popüler bir kural olarak, boşluklar (URL'lerde kullanılmasına izin verilmez) genellikle artı '+' karakteri kullanılarak da temsil edilir.
  • Karakterler, yukarıdaki grupta ayrılmış karakterler olarak bulunur ancak birbirlerinin yerine kullanılmaları gerekir. Örneğin, ?, URL'lerde sorgu dizesinin başlangıcını belirtmek için kullanılır. "? ve Gizemler" dizesini kullanmak istiyorsanız '?' karakterini kodlamanız gerekir.

URL olarak kodlanacak tüm karakterler, bir '%' karakteri ve UTF-8 karakterine karşılık gelen iki karakterlik onaltılık değer kullanılarak kodlanır. Örneğin, UTF-8'de 上海+中國, %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B olarak URL olarak kodlanır. ? and the Mysterians dizesi, %3F+and+the+Mysterians veya %3F%20and%20the%20Mysterians olarak URL olarak kodlanır.

Kodlama gerektiren yaygın karakterler

Kodlanması gereken bazı yaygın karakterler şunlardır:

Güvenli olmayan karakter Kodlanmış değer
Boşluk %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

Kullanıcı girişlerinden aldığınız bir URL'yi dönüştürmek bazen zor bir iş olabilir. Örneğin, bir kullanıcı "5. ve Ana Cad." olarak bir adres girebilir. Genel olarak, URL'nizi parçalarından oluşturmalısınız ve tüm kullanıcı girişlerini harf karakterleri olarak işlemelisiniz.

Ayrıca, tüm Google Haritalar Platformu web hizmetleri ve statik web API'leri için URL'ler 16.384 karakterle sınırlıdır. Çoğu hizmette bu karakter sınırına nadiren yaklaşılır. Ancak bazı hizmetlerde, uzun URL'lere neden olabilecek birkaç parametre bulunduğunu unutmayın.

Google API'lerinin Sonradan Kullanımı

Kötü tasarlanmış API istemcileri hem internet hem de Google sunucularına gerekenden daha fazla yük yükleyebilir. Bu bölümde, API istemcileri için bazı en iyi uygulamalar yer almaktadır. Bu en iyi uygulamaları izlemek, API'lerin yanlışlıkla kötüye kullanılması nedeniyle uygulamanızın engellenmesini önlemenize yardımcı olabilir.

Üstel Geri Alma

Nadir durumlarda isteğiniz yerine getirilirken bir şeyler ters gidebilir; 4XX veya 5XX HTTP yanıt kodu alabilirsiniz ya da istemcinizle Google'ın sunucusu arasındaki bir yerde TCP bağlantısı kesilebilir. Takip isteği, orijinal istek başarısız olduğunda başarılı olabileceğinden genellikle isteği yeniden denemek faydalı olur. Bununla birlikte, Google'ın sunucularına tekrar tekrar istek yapılmasını döngüye almak önemli değildir. Bu döngü davranışı, istemcinizle Google arasındaki ağı aşırı yükleyerek birçok taraf için sorunlara yol açabilir.

Denemeler arasında artan gecikmeleri kullanarak tekrar denemek daha iyi bir yaklaşımdır. Gecikme, genellikle her denemede üstel Geri Yükleme olarak bilinen bir yaklaşım olan çarpımsal bir faktörle artar.

Örneğin, bu isteği Time Zone API'ye göndermek isteyen bir uygulamayı düşünün:

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

Aşağıdaki Python örneğinde, isteğin eksponansiyel geri yüklemeyle nasıl yapılacağı gösterilmektedir:

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

Ayrıca uygulama çağrı zincirinde, hızlı bir şekilde tekrarlanan isteklere yol açan daha üst düzey yeniden deneme kodları olmadığından da emin olmalısınız.

Senkronize İstekler

Google'ın API'lerine yapılan senkronize edilmiş çok sayıda istek, Google'ın altyapısına yönelik bir Dağıtılmış Hizmet Reddi (DDoS) saldırısı gibi görünebilir ve uygun şekilde ele alınır. Bunu önlemek için API isteklerinin istemciler arasında senkronize edilmediğinden emin olmanız gerekir.

Örneğin, saati geçerli saat diliminde görüntüleyen bir uygulamayı düşünün. Bu uygulama büyük olasılıkla, görüntülenen saatin güncellenebilmesi için istemcinin işletim sisteminde alarm ayarlanır ve dakikanın başında uyandırılır. Uygulama, söz konusu alarmla ilişkili işlemin parçası olarak API çağrısı yapmamalıdır.

Sabit bir alarma yanıt olarak API çağrıları yapmak, API çağrılarının farklı cihazlar arasında bile zaman içinde eşit olarak dağıtılmak yerine dakikanın başlangıcına kadar senkronize edilmesine neden olduğu için kötüdür. Bunu yapan kötü tasarlanmış bir uygulama, her dakikanın başında trafikte normal seviyelerden altmış kat artışa neden olur.

Bunun yerine olası iyi bir tasarım, rastgele seçilen bir zamana ikinci bir alarm ayarlamaktır. Bu ikinci alarm etkinleştiğinde uygulama, ihtiyacı olan API'leri çağırır ve sonuçları depolar. Uygulama, dakikanın başında görüntüsünü güncellemek istediğinde API'yi tekrar çağırmak yerine önceden depolanan sonuçları kullanır. Bu yaklaşımla, API çağrıları zamanla eşit şekilde dağıtılır. Ayrıca ekran güncellendiğinde API çağrıları oluşturma işlemini geciktirmez.

Dakikanın başlangıcından ayrı olarak, hedeflemeye dikkat etmemeniz gereken diğer yaygın senkronizasyon zamanları da bir saatin başında ve her günün gece yarısında başlar.

Yanıtları İşleme

Bu bölümde, bu değerlerin web hizmeti yanıtlarından dinamik olarak nasıl çıkarılacağı açıklanmaktadır.

Google Haritalar web hizmetleri, anlaşılması kolay ama kullanıcı dostu olmayan yanıtlar sunar. Bir sorgu gerçekleştirirken bir veri kümesi görüntülemek yerine muhtemelen belirli birkaç değeri ayıklamak istersiniz. Genellikle, web hizmetinden yanıtları ayrıştırmak ve yalnızca ilginizi çeken değerleri ayıklamak istersiniz.

Kullandığınız ayrıştırma şeması, çıktıyı XML veya JSON biçiminde mi döndürdüğünüze bağlıdır. Halihazırda Javascript nesnesi biçiminde olan JSON yanıtları, istemcide JavaScript içinde işlenebilir. XML yanıtları, öğelerin XML biçimi içerisinde ele alınması için bir XML işlemcisi ve XML sorgu dili kullanılarak işlenmelidir. XML işleme kitaplıklarında yaygın olarak desteklendiği için XPath'i aşağıdaki örneklerde kullandık.

XML'yi XPath ile işleme

XML, veri alışverişi için kullanılan, görece olgunlaşmış bir yapılandırılmış bilgi biçimidir. JSON kadar hafif olmasa da XML, daha fazla dil desteği ve daha güçlü araçlar sağlar. Örneğin, Java'da XML işleme kodu, javax.xml paketlerinde yerleşik olarak bulunur.

XML yanıtlarını işlerken, öğelerin XML işaretlemesindeki mutlak konumlarda bulunduğunu varsaymak yerine, XML belgesindeki düğümleri seçmek için uygun bir sorgu dili kullanmanız gerekir. XPath, bir XML belgesindeki düğümleri ve öğeleri benzersiz bir şekilde tanımlamak için kullanılan bir dil söz dizimidir. XPath ifadeleri, XML yanıt belgesindeki belirli içerikleri tanımlamanızı sağlar.

XPath İfadeleri

XPath konusunda biraz bilgi sahibi olmak, sağlam bir ayrıştırma şeması geliştirmede oldukça yararlı olur. Bu bölümde, birden çok öğeyi ele almanıza ve karmaşık sorgular oluşturmanıza olanak tanıyarak XML belgesindeki öğelerin XPath ile nasıl ele alınacağına odaklanacağız.

XPath, dizin yolları için kullanılana benzer bir söz dizimi kullanarak XML belgesi içindeki öğeleri seçmek için ifadeleri kullanır. Bu ifadeler, DOM'unkine benzer hiyerarşik bir ağaç olan XML belgesi ağacındaki öğeleri tanımlar. XPath ifadeleri genel olarak açgözlüdür. Bu, sağlanan ölçütlerle eşleşen tüm düğümlerle eşleşeceklerini gösterir.

Örneklerimizi açıklamak için aşağıdaki soyut XML'i kullanacağız:

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

İfadelerde Düğüm Seçimi

XPath seçimleri düğümleri seçer. Kök düğüm belgenin tamamını kapsar. Bu düğümü "/" özel ifadesini kullanarak seçersiniz. Kök düğümün XML belgenizin en üst düzey düğümü olmadığını, aslında bu üst düzey öğenin bir seviye üzerinde bulunduğunu ve içinde bulunduğunu unutmayın.

Öğe düğümleri, XML belge ağacındaki çeşitli öğeleri temsil eder. Örneğin bir <WebServiceResponse> öğesi, yukarıdaki örnek hizmetimizde döndürülen üst düzey öğeyi temsil eder. Bağımsız düğümleri, başında "/" karakterinin olup olmamasıyla belirtilen mutlak veya göreli yollarla seçersiniz.

  • Mutlak yol: "/WebServiceResponse/result" ifadesi, <WebServiceResponse> düğümünün alt öğesi olan tüm <result> düğümlerini seçer. (Bu öğelerin ikisinin de "/" kök düğümünden aşağı indiğini unutmayın.)
  • Mevcut bağlamdaki göreli yol: "result" ifadesi, geçerli bağlamdaki herhangi bir <result> öğesiyle eşleşir. Web hizmeti sonuçlarını genellikle tek bir ifadeyle işlediğinizden genellikle bağlam konusunda endişelenmeniz gerekmez.

Bu ifadelerden her biri, çift eğik çizgiyle ("//") belirtilen bir joker karakter yolu eklenerek geliştirilebilir. Bu joker karakter, araya giren yolda sıfır veya daha fazla öğenin eşleşebileceğini belirtir. Örneğin "//formatted_address" XPath ifadesi, geçerli belgede bu adın tüm düğümleriyle eşleşir. //viewport//lat ifadesi, <viewport> öğesini üst öğe olarak izleyebilen tüm <lat> öğeleriyle eşleşir.

Varsayılan olarak, XPath ifadeleri tüm öğelerle eşleşir. Köşeli parantez ([]) içine alınmış bir predicate sağlayarak ifadeyi belirli bir öğeyle eşleşecek şekilde kısıtlayabilirsiniz. Örneğin, XPath ifadesi "/GeocodeResponse/result[2]" her zaman ikinci sonucu döndürür.

İfade Türü
Root düğüm
XPath İfadesi:  "/"
Seçim:
    <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>
    
Mutlak Yol
XPath İfadesi:  "/WebServiceResponse/result"
Seçim:
    <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>
    
Joker Karakterli Yol
XPath İfadesi:  "/WebServiceResponse//location"
Seçim:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Yüklemli Yol
XPath İfadesi:  "/WebServiceResponse/result[2]/message"
Seçim:
    <message>The secret message</message>
    
İlk result öğesinin tüm doğrudan alt öğeleri
XPath İfadesi:  "/WebServiceResponse/result[1]/*"
Seçim:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
type metni "sample" olan bir result öğesinin name öğesi.
XPath İfadesi:  "/WebServiceResponse/result[type/text()='sample']/name"
Seçim:
    Sample XML
    

Öğeleri seçerken yalnızca bu nesnelerin içindeki metni değil, düğümleri seçtiğinizi unutmamak önemlidir. Genellikle, eşleşen tüm düğümlerde yineleme işlemi uygulamak ve metni çıkarmak istersiniz. Metin düğümlerini doğrudan da eşleyebilirsiniz. Aşağıdaki Metin Düğümleri bölümüne bakın.

XPath'in özellik düğümlerini de desteklediğini unutmayın; ancak, tüm Google Haritalar web hizmetleri öğeleri öznitelik olmadan sunar, bu nedenle özelliklerin eşleştirilmesi gerekmez.

İfadelerde Metin Seçimi

XML belgesindeki metin, XPath ifadelerinde bir metin düğümü operatörü aracılığıyla belirtilir. Bu operatör "text()", belirtilen düğümden metin ayıklandığını gösterir. Örneğin, "//formatted_address/text()" XPath ifadesi, <formatted_address> öğeleri içindeki tüm metni döndürür.

İfade Türü
Tüm metin düğümleri (boşluklar dahil)
XPath İfadesi:  "//text()"
Seçim:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Metin Seçimi
XPath İfadesi:  "/WebServiceRequest/result[2]/message/text()"
Seçim:
    The secret message
    
Bağlama duyarlı seçim
XPath İfadesi:  "/WebServiceRequest/result[type/text() = 'sample']/name/text()"
Seçim:
    Sample XML
    

Alternatif olarak, bir ifadeyi değerlendirip bir düğüm grubunu döndürebilir ve ardından bu "düğüm kümesinin" üzerinde iterasyon yaparak metni her düğümden ayıklayabilirsiniz. Bu yaklaşımı aşağıdaki örnekte kullanıyoruz.

XPath hakkında daha fazla bilgi için XPath W3C Spesifikasyonu'na bakın.

Java'da XPath değerlendirmesi

Java, XML'i ayrıştırma ve javax.xml.xpath.* paketi içinde XPath ifadelerini kullanma için kapsamlı desteğe sahiptir. Bu nedenle, bu bölümdeki örnek kodda XML'in nasıl işleneceğini ve XML hizmet yanıtlarından verilerin nasıl ayrıştırılacağını göstermek için Java kullanılmaktadır.

Java kodunuzda XPath'i kullanmak için önce bir XPathFactory örneğini örneklendirmeniz ve bu fabrikada bir XPath nesnesi oluşturmak için newXPath() yöntemini çağırmanız gerekir. Bu nesne, daha sonra evaluate() yöntemini kullanarak geçirilen XML ve XPath ifadelerini işleyebilir.

XPath ifadelerini değerlendirirken, döndürülebilecek tüm olası "düğüm kümelerini" tekrarladığınızdan emin olun. Bu sonuçlar Java kodunda DOM düğümleri olarak döndürüldüğünden, bir NodeList nesnesinde bu tür birden çok değeri yakalamanız ve bu düğümlerdeki metinleri veya değerleri çıkarmak için nesnenin üzerinde iterasyon yapmanız gerekir.

Aşağıdaki kod, bir XPath nesnesinin nasıl oluşturulacağını, buna XML ve XPath ifadesinin nasıl atanacağını ve ilgili içeriği yazdırmak için ifadenin nasıl değerlendirileceğini göstermektedir.

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