Wypróbuj nową generację funkcji macierzy odległości z interfejsem Routes API, który jest teraz dostępny w wersji przedpremierowej.

Sprawdzone metody korzystania z usług internetowych interfejsu API odległości

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Usługi internetowe Google Maps Platform to zbiory interfejsów HTTP dla usług Google, z których pochodzą dane geograficzne.

W tym przewodniku opisano kilka typowych praktyk przydatnych przy konfigurowaniu żądań usługi internetowej i przetwarzaniu odpowiedzi na usługi. Pełną dokumentację interfejsu DISTANCE Matrix API znajdziesz w przewodniku dla programistów.

Co to jest usługa internetowa?

Usługi internetowe Google Maps Platform to interfejs służący do wysyłania żądań danych interfejsu API Map Google z usług zewnętrznych i korzystania z danych w aplikacjach Map Google. Te usługi są zaprojektowane tak, by można było z nimi korzystać, zgodnie z ograniczeniami licencji w Warunkach korzystania z Google Maps Platform.

Usługi internetowe interfejsów API Map Google używają żądań HTTP(S) do określonych adresów URL, przekazując parametry URL lub dane POST w formacie JSON jako argumenty usług. Zwykle te usługi zwracają dane w żądaniu HTTP(S) w formacie JSON lub XML do analizy lub przetwarzania przez aplikację.

Typowe żądanie interfejsu DISTANCE Matrix API ma zazwyczaj następującą formę:

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

gdzie output wskazuje format odpowiedzi (zwykle json lub xml).

Uwaga: wszystkie aplikacje interfejsu DISTANCE Matrix API wymagają uwierzytelnienia. Dowiedz się więcej o danych uwierzytelniających.

Dostęp SSL/TLS

Protokół HTTPS jest wymagany w przypadku wszystkich żądań w Google Maps Platform, które korzystają z kluczy interfejsu API lub zawierają dane użytkowników. Żądania wysłane przez HTTP, które zawierają dane wrażliwe, mogą zostać odrzucone.

Tworzenie prawidłowego adresu URL

Może Ci się wydawać, że URL jest prawidłowy, ale nie do końca. Adres URL wpisany na pasku adresu w przeglądarce może na przykład zawierać znaki specjalne (np."上海+中國"). Przeglądarka musi we własnym zakresie przetłumaczyć te znaki na inne kodowanie. Na podstawie tego samego tokena każdy kod, który generuje lub akceptuje dane wejściowe UTF-8, może traktować adresy URL ze znakami UTF-8 jako „"valid"”, ale musi też tłumaczyć te znaki przed wysłaniem ich na serwer WWW. Ten proces jest nazywany kodowaniem adresów URL lub kodowaniem procentowym.

Znaki specjalne

Musimy przetłumaczyć znaki specjalne, ponieważ wszystkie adresy URL muszą być zgodne ze składnią podaną w specyfikacji Jednolitego identyfikatora zasobu (URI). Oznacza to, że adresy URL mogą zawierać tylko specjalny podzbiór znaków ASCII: znane symbole alfanumeryczne i niektóre zarezerwowane znaki do wykorzystania jako znaki kontrolne w adresach URL. Ta tabela zawiera podsumowanie tych znaków:

Podsumowanie prawidłowych znaków adresu URL
UstawznakuWykorzystanie adresu URL
Znaki alfanumeryczne A b k d e g g h j k l l m z p o Ciągi tekstowe, wykorzystanie schematu (http), port (8080) itd.
Niezarezerwowane – _ . ~ Ciągi tekstowe
Zarezerwowane ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Steruj znakami lub ciągami tekstowymi

Podczas tworzenia prawidłowego adresu URL upewnij się, że zawiera on tylko te znaki z tabeli Podsumowanie prawidłowych znaków adresu URL. Wprowadzenie tego zestawu znaków w adresie URL zazwyczaj powoduje 2 problemy – pominięcie lub pominięcie:

  • Znaki, które chcesz obsługiwać, istnieją poza powyższym zestawem. Na przykład znaki w językach obcych, takie jak 上海+中國, muszą być zakodowane przy użyciu powyższych znaków. Zgodnie z obowiązującą konwencją spacje (niedozwolone w adresach URL) są często reprezentowane przez znak '+'.
  • Znaki wchodzące w skład powyższych znaków są zastrzeżone, ale trzeba ich używać dosłownie. Na przykład dyrektywa ? jest używana w adresach URL do wskazania początku ciągu zapytania. Jeśli chcesz użyć ciągu znaków „Tajemnice” i „Tajemnice”, musisz zakodować znak '?'.

Wszystkie znaki do zakodowania w adresie URL są kodowane za pomocą znaku '%' i dwuznakowego wartości szesnastkowej odpowiadającej ich kodowi UTF-8. Na przykład ciąg 上海+中國 w UTF-8 zostanie zakodowany jako %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B. Ciąg ? and the Mysterians byłby zakodowany na potrzeby tego adresu URL jako %3F+and+the+Mysterians lub %3F%20and%20the%20Mysterians.

Typowe znaki, które wymagają kodowania

Typowe znaki, które należy zakodować:

Niebezpieczny znak Wartość zakodowana
Spacja %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

Konwertowanie adresu URL otrzymanego z danych wejściowych użytkownika może być trudne. Na przykład użytkownik może wpisać adres w ciągu „ "5th&Main St." Adres URL należy zwykle tworzyć z jego części, traktując dane wejściowe użytkownika jako znaki literału.

Adresy URL mogą zawierać maksymalnie 8192 znaki we wszystkich usługach internetowych Google Maps Platform i w statycznych interfejsach API. W przypadku większości usług limit znaków jest rzadko osiągany. Pamiętaj jednak, że niektóre usługi mają kilka parametrów, które mogą prowadzić do długiego adresu URL.

Kontrola dostępu do interfejsów API Google

Źle zaprojektowane klienty interfejsu API mogą zajmować więcej miejsca niż to konieczne w przypadku serwerów internetowych i Google. Ta sekcja zawiera sprawdzone metody dotyczące klientów korzystających z interfejsów API. Postępując zgodnie z tymi sprawdzonymi metodami, możesz zapobiec blokowaniu aplikacji w wyniku niezamierzonego nadużycia interfejsów API.

Exponential Backoff

W rzadkich przypadkach może się zdarzyć, że coś poszło nie tak. Możesz otrzymać kod odpowiedzi HTTP 4XX lub 5XX albo połączenie TCP może zakończyć się niepowodzeniem w miejscu między klientem a serwerem Google. Często warto ponawiać żądanie, ponieważ kolejna prośba może się nie udać. Ważne jest jednak, aby nie powtarzać pętli wielokrotnego wysyłania żądań do serwerów Google. Takie pętle mogą przeciążać sieć między klientem a Google, powodując wiele problemów.

Lepszym sposobem jest ponowienie próby z późniejszym opóźnieniem między kolejnymi próbami. Opóźnienia są zwykle mnożone przez współczynnik mnożony przez każdą próbę, czyli w postaci wykładniczego ponowienia.

Weźmy na przykład aplikację, która chce przesłać żądanie do interfejsu Time Zone API:

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

Poniższy przykład Pythona pokazuje, jak wykonać żądanie z wykładniczym wzmocnieniem:

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

Zwróć uwagę na to, aby w łańcuchu wywołań aplikacji nie pojawiał się kod ponawiania próby, który prowadzi do powtarzających się żądań w szybkiej kolejności.

Zsynchronizowane żądania

Duża liczba zsynchronizowanych żądań do interfejsów API Google może wyglądać jak rozproszona odmowa usługi (DDoS) w infrastrukturze Google i z odpowiednim zachowaniem jest traktowana. Aby tego uniknąć, sprawdź, czy żądania API nie są synchronizowane między klientami.

Weźmy na przykład aplikację, która wyświetla godzinę w bieżącej strefie czasowej. Ta aplikacja prawdopodobnie ustawi alarm w systemie operacyjnym klienta, który obudzi ją na początku minuty, aby można było zmienić wyświetlany czas. Aplikacja nie powinna wywoływać żadnych interfejsów API w ramach przetwarzania powiązanego z tym alarmem.

Wykonywanie wywołań interfejsu API w odpowiedzi na stały alarm jest niewłaściwe, ponieważ prowadzi do synchronizacji wywołań interfejsu API na początku minuty, nawet między różnymi urządzeniami, a nie równomiernym rozkładem w czasie. Nieodpowiednio zaprojektowana aplikacja może powodować wzrost natężenia ruchu na poziomie co najmniej 60 razy na początku każdej minuty.

Zamiast tego możesz na przykład ustawić drugi alarm o wybranych losowo porach. Gdy ten drugi alarm uruchomi się, aplikacja wywoła wszelkie potrzebne interfejsy API i zapisze wyniki. Gdy aplikacja chce zaktualizować wyświetlacz na początku minuty, używa ponownie zapisanych wyników, zamiast ponownie wywoływać interfejs API. Dzięki temu wywołania interfejsu API są równomiernie rozkładane w czasie. Co więcej, wywołania interfejsu API nie opóźniają renderowania podczas aktualizowania wyświetlacza.

Oprócz początku minuty inne typowe godziny synchronizacji, których należy nie kierować, to rozpoczęcia o godzinie i północ tego samego dnia.

Przetwarzanie odpowiedzi

W tej sekcji opisano, jak dynamicznie wyodrębniać te wartości z odpowiedzi usługi internetowej.

Usługi internetowe Map Google udostępniają odpowiedzi, które są łatwe do zrozumienia, ale zrozumiałe dla użytkowników. Podczas wykonywania zapytania zamiast wyświetlania zbioru danych lepiej jest wyodrębnić kilka konkretnych wartości. Przeanalizuj zazwyczaj odpowiedzi z usługi internetowej i wyodrębnij tylko te wartości, które Cię interesują.

Używany schemat analizowania zależy od tego, czy zwracasz dane wyjściowe w formacie XML, czy JSON. Odpowiedzi JSON (w postaci obiektów JavaScript) mogą być przetwarzane w samym kodzie JavaScript w kliencie. Odpowiedzi XML powinny być przetwarzane z użyciem procesora XML i języka zapytania XML do rozpatrywania elementów w formacie XML. W poniższych przykładach używamy ciągu XPath, ponieważ jest on często obsługiwany przez biblioteki przetwarzania XML.

Przetwarzanie pliku XML za pomocą XPath

XML to stosunkowo dojrzały format informacji strukturalnych używany do wymiany danych. Choć nie jest tak łatwy jak JSON, XML zapewnia większą obsługę języka i bardziej niezawodne narzędzia. Na przykład w pakietach javax.xml jest wbudowany kod do przetwarzania plików XML w języku Java.

Podczas przetwarzania odpowiedzi XML przy użyciu węzłów musisz użyć odpowiedniego języka zapytania, zamiast zakładać, że elementy znajdują się w bezwzględnych pozycji w znacznikach XML. XPath to składnia języka, która służy do jednoznacznego opisywania węzłów i elementów w dokumencie XML. Wyrażenia XPath pozwalają zidentyfikować określoną treść w dokumencie odpowiedzi XML.

Wyrażenia XPath

Znajomość metody XPath znacznie ułatwia opracowanie solidnego schematu analizy. W tej sekcji skupimy się na tym, jak elementy w dokumencie XML są rozwiązywane za pomocą XPath, co umożliwia obsługę wielu elementów i tworzenie złożonych zapytań.

XPath używa wyrażeń do wybierania elementów w dokumencie XML, używając składni podobnej do składni używanej w ścieżkach katalogów. Te wyrażenia identyfikują elementy w drzewie dokumentu XML, które jest hierarchiczne drzewo podobne do drzewa DOM. Wyrażenia XPath są zwykle zachmurzone, co oznacza, że będą pasowały do wszystkich węzłów spełniających podane kryteria.

Aby zilustrować nasze przykłady, użyjemy poniższego abstrakcyjnego pliku 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>

Wybór węzłów w wyrażeniach

W ścieżkach XPath wybierz węzły. Węzeł główny obejmuje cały dokument. Ten węzeł jest wybierany za pomocą specjalnego wyrażenia /&quot. Pamiętaj, że węzeł główny nie jest węzłem najwyższego poziomu dokumentu XML; w rzeczywistości znajduje się o jeden poziom powyżej tego elementu najwyższego poziomu i zawiera go.

Węzły elementów reprezentują różne elementy w drzewie dokumentów XML. Na przykład element <WebServiceResponse> reprezentuje element najwyższego poziomu zwracany w przykładowej usłudze powyżej. Poszczególne węzły wybiera się ze ścieżek bezwzględnych lub względnych wskazujących obecność lub brak głównego znaku/".

  • Ścieżka bezwzględna: wyrażenie "/WebServiceResponse/result" wybiera wszystkie węzły <result>, które są elementami podrzędnymi węzła <WebServiceResponse>. (Pamiętaj, że oba te elementy należą do węzła głównego "/".).
  • Względna ścieżka z bieżącego kontekstu: wyrażenie "result" pasuje do wszystkich elementów <result> w bieżącym kontekście. Zasadniczo nie musisz przejmować się kontekstem, ponieważ zwykle przetwarzasz wyniki usług internetowych za pomocą jednego wyrażenia.

Każde z tych wyrażeń może zostać uzupełnione przez dodanie ścieżki z symbolem wieloznacznym oznaczonej podwójnym ukośnikiem (&&t;//"). Ten symbol wieloznaczny oznacza, że w ścieżce przejściowej może wystąpić zero lub więcej elementów. Wyrażenie XPath np. //formatted_address, " na przykład będzie pasować do wszystkich węzłów o tej nazwie w bieżącym dokumencie. Wyrażenie //viewport//lat dopasuje wszystkie elementy <lat>, które mogą śledzić <viewport> jako element nadrzędny.

Domyślnie wyrażenia XPath pasują do wszystkich elementów. Możesz ograniczyć wyrażenie do określonego elementu, podając predykat, który znajduje się w nawiasach kwadratowych ([]). Wyrażenie XPath "/GeocodeResponse/result[2] zawsze zwraca drugi wynik.

Typ wyrażenia
Węzeł główny
Wyrażenie XPath: &"/"
Wybór:
    <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>
    
Ścieżka bezwzględna
Wyrażenie XPath: &"/WebServiceResponse/result"
Wybór:
    <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>
    
Ścieżka z symbolem wieloznacznym
Wyrażenie XPath: &"/WebServiceResponse//location"
Wybór:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Ścieżka z predykatem
Wyrażenie XPath: &"/WebServiceResponse/result[2]/message"
Wybór:
    <message>The secret message</message>
    
Wszystkie dzieci bezpośrednie z pierwszych result
Wyrażenie XPath: &"/WebServiceResponse/result[1]/*"
Wybór:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
name elementu result, którego tekst type to "sample."
Wyrażenie XPath: &"/WebServiceResponse/result[type/text()='sample']/name"
Wybór:
    Sample XML
    

Pamiętaj, że przy wybieraniu elementów musisz wybrać węzły, a nie tekst w tych obiektach. Zasadniczo najlepiej jest iterować we wszystkich dopasowanych węzłach i wyodrębniać tekst. Możesz też bezpośrednio dopasować węzły tekstowe (patrz Węzły tekstowe poniżej).

XPath obsługuje też węzły, ale wszystkie usługi internetowe Map Google obsługują elementy bez atrybutów, więc dopasowanie atrybutów nie jest konieczne.

Zaznaczanie tekstu w wyrażeniach

Tekst w dokumencie XML jest określany w wyrażeniach XPath za pomocą operatora węzła tekstowego. Ten operator &"text()wskazuje wyodrębnienie tekstu ze wskazanego węzła. Na przykład wyrażenie XPath "//formatted_address/text()" zwraca cały tekst w elementach <formatted_address>.

Typ wyrażenia
Wszystkie węzły tekstowe (w tym odstępy)
Wyrażenie XPath: &"//text()"
Wybór:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Zaznaczanie tekstu
Wyrażenie XPath: &"/WebServiceRequest/result[2]/message/text()"
Wybór:
    The secret message
    
Wybór zależny od kontekstu
Wyrażenie XPath: &"/WebServiceRequest/result[type/text() = 'sample']/name/text()"
Wybór:
    Sample XML
    

Możesz też ocenić wyrażenie i zwrócić zestaw węzłów, a następnie iterować nad tym &zestawem węzłów i wyodrębniać tekst z każdego węzła. W tym przykładzie używamy tego podejścia.

Więcej informacji o XPath znajdziesz w specyfikacji XPath W3C.

Ocena XPath w Javie

Obsługa JavaScript w analizie kodu XML i wykorzystywaniu wyrażeń XPath w pakiecie javax.xml.xpath.* jest bardzo skuteczna. Z tego względu przykładowy kod w tej sekcji korzysta z języka Java do ilustrowania sposobu przetwarzania danych XML i analizowania danych z odpowiedzi usługi XML.

Aby użyć XPath w kodzie Java, musisz najpierw utworzyć instancję XPathFactory i wywołać newXPath() w tej fabryce, aby utworzyć obiekt XPath . Ten obiekt może następnie przetwarzać przekazywane wyrażenia XML i XPath za pomocą metody evaluate().

Oceniając wyrażenia XPath, pamiętaj o powtarzaniu możliwych wszelkich zestawów &węzłów, które mogą być zwracane. Wyniki te są zwracane w kodzie Java w postaci węzłów DOM, dlatego musisz zarejestrować tak wiele wartości w obiekcie NodeList i powtarzać ten obiekt, aby wyodrębnić tekst lub wartości z węzłów.

Poniższy kod pokazuje, jak utworzyć obiekt XPath, przypisać go do pliku XML i wyrażenia XPath oraz ocenić wyrażenie, aby wydrukować odpowiednią treść.

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