Best Practices für die Verwendung von Geocoding API-Webdiensten

Die Google Maps Platform-Webdienste sind eine Sammlung von HTTP-Schnittstellen zu Google -Dienste, die geografische Daten für Ihre Kartenanwendungen bereitstellen.

In diesem Leitfaden werden einige gängige Vorgehensweisen beschrieben, die bei der Einrichtung der Webdienst und Dienstantworten verarbeiten können. Weitere Informationen finden Sie im Entwicklerhandbuch. finden Sie die vollständige Dokumentation der Geocoding API.

Was ist ein Webdienst?

Google Maps Platform-Webdienste sind eine Schnittstelle zum Anfordern von Maps API-Daten von externe Dienste und die Verwendung der Daten in Ihren Maps-Anwendungen. Diese Dienste sind die zur Verwendung in Verbindung mit einer Karte entwickelt wurden, gemäß den Lizenzbeschränkungen in den Nutzungsbedingungen für die Google Maps Platform beschrieben.

Die Google Maps APIs-Webdienste verwenden HTTP(S)-Anfragen an bestimmte URLs, wobei URL-Parameter und/oder POST-Daten im JSON-Format als Argumente für die Dienste. Im Allgemeinen geben diese Dienste Daten in der Antworttext zum Parsen im JSON- oder XML-Format und/oder Verarbeitung durch Ihre Anwendung.

Eine typische Geocoding API-Anfrage ist im Allgemeinen folgendes Formular:

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

Dabei gibt output das Antwortformat an (normalerweise json oder xml).

Hinweis: Alle Geocoding API-Anwendungen erfordern eine Authentifizierung. Weitere Informationen zu Anmeldedaten für die Authentifizierung

SSL/TLS-Zugriff

HTTPS ist für alle Google Maps Platform-Anfragen erforderlich, bei denen API-Schlüssel verwendet werden oder die Nutzer Daten. Anfragen über HTTP, die sensible Daten enthalten, können abgelehnt werden.

Gültige URL erstellen

Es mag den Anschein haben, dass „gültige“ URLs eine Selbstverständlichkeit sind. Das ist jedoch nicht der Fall. So kann beispielsweise eine URL, die in die Adresszeile eines Browsers eingegeben wird, Sonderzeichen wie "上海+中國" enthalten. Der Browser muss diese Zeichen vor der Übertragung intern in eine andere Codierung umwandeln. Ebenso ist es möglich, dass Code, der UTF-8-Eingaben erzeugt oder akzeptiert, URLs mit UTF-8-Zeichen als „gültig“ behandelt; diese Zeichen müssten jedoch vor dem Senden an einen Webbrowser ebenfalls umgewandelt werden. Dieser Vorgang wird als URL-Codierung oder Prozentcodierung bezeichnet.

Sonderzeichen

Sonderzeichen müssen umgewandelt werden, da alle URLs der Syntax entsprechen müssen, die in der Spezifikation Uniform Resource Identifier (URI) angegeben ist. Das bedeutet, dass URLs nur einen Teil der ASCII-Zeichen enthalten dürfen: die bekannten alphanumerischen Symbole und einige reservierte Zeichen, die in den URLs als Steuerzeichen dienen. Hier eine Übersicht:

Gültige URL-Zeichen
ZeichensatzcharactersVerwendung in der URL
Alphanumerisch 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 Textstrings, Schemas (http), Portangaben (8080) usw.
Nicht reserviert - _ . ~ Textstrings
Reserviert ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Steuerzeichen und/oder Textstrings

Bei der Erstellung einer gültigen URL müssen Sie darauf achten, dass sie nur die Zeichen enthält, die in den . Die Anpassung der URL an diesen Zeichensatz führt in der Regel zu zwei Problemen, nämlich dass Zeichen weggelassen oder ersetzt werden müssen:

  • Die Zeichen, die Sie verarbeiten möchten, sind nicht im obigen Zeichensatz enthalten. So müssen beispielsweise Zeichen ausländischer Sprachen, wie 上海+中國, mithilfe der oben angegebenen Zeichen codiert werden. Auch werden Leerzeichen, die innerhalb von URLs nicht zulässig sind, entsprechend den geltenden Konventionen oftmals durch das Zeichen '+' dargestellt.
  • Die Zeichen sind im obigen Zeichensatz als reservierte Zeichen enthalten, müssen aber im ursprünglichen Sinn des Zeichens verwendet werden. So wird beispielsweise ? in URLs für den Beginn eines Abfragestrings verwendet. Möchten Sie es stattdessen für den Text „? and the Mysterions“ verwenden, müssen Sie das Zeichen '?' codieren.

Alle Zeichen, die als URL codiert werden sollen, werden mithilfe des Zeichens '%' und eines Hexadezimalwerts aus zwei Zeichen codiert, der ihrem UTF-8-Zeichen entspricht. So würde zum Beispiel der UTF-8-String 上海+中國 durch die URL-Codierung in %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B umgewandelt. Und aus ? and the Mysterians würde %3F+and+the+Mysterians oder %3F%20and%20the%20Mysterians werden.

Häufig vorkommende Zeichen, die codiert werden müssen

Folgende häufig vorkommende Zeichen müssen codiert werden:

Unsicheres Zeichen Codierter Wert
Leerzeichen %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

Die Konvertierung von URLs, die aus Nutzereingaben empfangen werden, kann manchmal Probleme mit sich bringen. Beispielsweise kann ein Nutzer eine Adresse als „5th&Main St.“ eingeben. Im Allgemeinen sollten Sie die URL aus ihren Teilen erstellen und jede Nutzereingabe wortwörtlich betrachten.

Außerdem sind URLs für alle Google Maps Platform-Webdienste und statischen Web APIs auf 16.384 Zeichen beschränkt. Bei den meisten Diensten wird diese Begrenzung selten erreicht. Beachten Sie jedoch, dass bestimmte Dienste einige Parameter haben, die zu langen URLs führen können.

Respektvolle Nutzung der Google APIs

Schlecht konzipierte API-Clients können sowohl das Internet als auch auf den Google-Servern. Dieser Abschnitt enthält einige bewährte Methoden für Kunden der APIs. Folge ich Mit diesen Best Practices können Sie vermeiden, dass Ihre Anwendung wegen unbeabsichtigtem Missbrauch von die APIs.

Fehler und Wiederholversuche

Informationen zu den Antwortcodes UNKNOWN_ERROR oder OVER_QUERY_LIMIT vom Geocoding API, Informationen zur Verwaltung von Fehlern und Wiederholungsversuchen

Exponential Backoff

In seltenen Fällen kann bei der Verarbeitung Ihrer Anfrage ein Fehler auftreten. erhalten Sie möglicherweise eine 4XX- oder 5XX-HTTP- oder die TCP-Verbindung zwischen Ihrem Client und dem Server. Häufig lohnt es sich, die Anfrage zu wiederholen, Die Folgeanfrage kann erfolgreich sein, wenn die ursprüngliche Anfrage fehlgeschlagen ist. Es ist jedoch wichtig, nicht einfach wiederholt Anfragen an die Server von Google. Dieses Schleifenverhalten kann die Netzwerk zwischen Ihrem Client und Google verursacht, was für viele Parteien zu Problemen führt.

Ein besserer Ansatz ist es, wiederholte Versuche in immer größeren Abständen durchzuführen. Normalerweise die Verzögerung bei jedem Versuch um einen multiplikativen Faktor erhöht. Dieser Ansatz wird als Exponentieller Backoff:

Nehmen wir als Beispiel eine Anwendung, die diese Anfrage an die Time Zone API:

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

Im folgenden Beispiel mit Python wird gezeigt, wie die Anforderung mit exponentiellem Backoff durchgeführt wird:

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

Sie sollten außerdem darauf achten, dass sich im Anwendungsaufruf kein Wiederholungscode weiter oben befindet. die schnell hintereinander wiederholte Anfragen führen.

Synchronisierte Anforderungen

Eine große Anzahl synchronisierter Anfragen an die APIs von Google kann wie eine verteilte Denial-of-Service-Angriff (DDoS) auf die Google-Infrastruktur und werden entsprechend gehandhabt. Bis vermeiden, sollten Sie sicherstellen, dass API-Anfragen nicht synchronisiert werden. zwischen den Auftraggebenden.

Angenommen, eine Anwendung zeigt die Zeit in der aktuellen Zeitzone an. Diese App wird wahrscheinlich einen Alarm im Client-Betriebssystem einstellen, um den Ruhemodus zu beenden den Beginn der Minute, damit die angezeigte Zeit aktualisiert werden kann. Die Anwendung sollte im Rahmen der Verarbeitung dieses Alarms keine API-Aufrufe ausführen.

API-Aufrufe als Reaktion auf einen behobenen Alarm sind nicht sinnvoll, da die API-Aufrufe dann bis zum Anfang der Minute synchronisiert, sogar zwischen verschiedenen Geräten. gleichmäßig über den Zeitraum verteilt. Eine schlecht konzipierte Anwendung, die dies tut, führt zu einer Spitze zu Beginn jeder Minute auf das sechzigfache Normalniveau.

Stattdessen wird bei einer guten Lösung ein zweiter Alarm für eine zufällig gewählte Zeit festgelegt. Wenn dieser zweite Alarm ausgelöst wird, ruft die Anwendung alle benötigten APIs auf und speichert die Ergebnisse. Wenn die Anzeige der Anwendung zu Beginn der Minute aktualisiert werden soll, verwendet sie die zuvor gespeicherten Ergebnisse zu erhalten, anstatt die API noch einmal aufzurufen. Bei diesem Ansatz werden API-Aufrufe gleichmäßig über einen Zeitraum verteilt. Außerdem verzögern die API-Aufrufe das Rendering nicht, wenn die Anzeige die gerade aktualisiert werden.

Abgesehen vom Beginn der Minute sollten Sie auf andere gängige Synchronisierungszeiten achten, nicht zu Beginn einer Stunde und zu Beginn jedes Tages um Mitternacht erfolgen.

Verarbeiten von Antworten

In diesem Abschnitt wird erklärt, wie Sie diese Werte dynamisch aus den Webdienstantworten extrahieren.

Die Google Maps-Webdienste liefern Antworten, die einfach verstehen, aber nicht gerade nutzungsfreundlich. Wenn Sie eine Abfrage durchführen, Daten anzuzeigen, möchten Sie wahrscheinlich einige spezifische Werte. Generell sollten Sie Antworten aus dem Web und extrahieren nur die Werte, die Sie interessieren.

Welches Parsing-Schema Sie verwenden, hängt davon ab, ob Sie im XML- oder JSON-Format ausgegeben. JSON-Antworten, die bereits in Form von JavaScript-Objekte, können in JavaScript selbst verarbeitet werden auf der Kundschaft. XML-Antworten sollten mit einem XML-Prozessor verarbeitet werden und einer XML-Abfragesprache, um Elemente innerhalb des XML-Formats anzusprechen. Wir verwenden XPath im folgenden Beispielen, da dies bei der XML-Verarbeitung häufig unterstützt wird. Bibliotheken.

Verarbeiten von XML mit XPath

XML ist ein relativ ausgereiftes Format für strukturierte Informationen, das für Datenaustausch. Obwohl sie nicht so schlank ist wie JSON, bietet mehr Sprachunterstützung und robustere Tools. Code für ist beispielsweise die Verarbeitung von XML in Java in den javax.xml Paket.

Bei der Verarbeitung von XML-Antworten sollten Sie eine geeignete Methode Abfragesprache zur Auswahl von Knoten im XML-Dokument als angenommen, dass sich die Elemente an absoluten Positionen XML-Markup. XPath ist eine Sprachsyntax zur eindeutigen Beschreibung von Knoten und Elementen. in einem XML-Dokument. Mit XPath-Ausdrücken können Sie bestimmte Inhalte im XML-Antwortdokument enthalten.

XPath-Ausdrücke

Ein gewisses Maß an Vertrautheit mit XPath ist wichtig, um die Entwicklung ein robustes Parsing-Schema. In diesem Abschnitt geht es darum, in einem XML-Dokument über XPath adressiert werden, mehrere Elemente zu berücksichtigen und komplexe Abfragen zu erstellen.

XPath verwendet Ausdrücke, um Elemente innerhalb einer XML auszuwählen. -Dokument mit einer Syntax, die der für Verzeichnispfade ähnelt. Diese Ausdrücke identifizieren Elemente in einem XML-Dokument , einer hierarchischen Baumstruktur ähnlich dem DOM. XPath-Ausdrücke sind „gierig“, d. h., sie stimmt mit allen Knoten überein, die den angegebenen Kriterien entsprechen.

Wir verwenden die folgende abstrakte XML, um unsere Beispiele:

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

Auswahl von Knoten in Ausdrücken

Mit der XPath-Auswahl werden Knoten ausgewählt. Der Stammknoten das gesamte Dokument umfasst. Sie wählen diesen Knoten mit den Spezialausdruck „/“. Beachten Sie, dass der Stamm Der Knoten ist nicht der oberste Knoten des XML-Dokuments. eigentlich befindet es sich eine Ebene über diesem Element der obersten Ebene und enthält .

Elementknoten stellen die verschiedenen Elemente in der XML-Datei dar. Dokumentstruktur. Ein <WebServiceResponse>-Element stellt beispielsweise das oberste Element dar, das in unserem Beispieldienst oben. Sie wählen einzelne Knoten entweder über absolute oder relative Pfade, die durch das Vorhandensein oder Fehlen eines vorangestellten "/" Zeichen.

  • Absoluter Pfad: „/WebServiceResponse/result“ Ausdruck wählt alle <result>-Knoten aus, die sind Kinder von <WebServiceResponse> Knoten. (Beachten Sie, dass beide Elemente vom Stamm abstammen. Knoten „/“.)
  • Relativer Pfad bezogen auf den aktuellen Kontext: der Ausdruck „result“ würde mit allen <result> übereinstimmen Elemente im aktuellen Kontext. Im Allgemeinen sollten Sie Kontext zu berücksichtigen, da es normalerweise um Web- Dienstergebnisse über einen einzigen Ausdruck.

Jeder dieser Ausdrücke kann durch Addition eines Platzhalterpfads, der durch einen doppelten Schrägstrich ("//") angegeben wird. Dieser Platzhalter gibt an, dass null oder mehr Elemente im den dazwischenliegenden Pfad. Der XPath-Ausdruck „//formatted_address“ zum Beispiel alle Knoten mit diesem Namen im aktuellen Dokument. Der Ausdruck //viewport//lat stimmt mit allen <lat>-Elemente, die <viewport> verfolgen können als Elternteil.

Standardmäßig werden durch XPath-Ausdrücke alle übereinstimmenden Elemente ausgewählt. Sie können die Den Ausdruck so, dass er mit einem bestimmten Element übereinstimmt. Dazu wird ein Prädikat angegeben. in eckigen Klammern ([]). XPath gibt der Ausdruck "/GeocodeResponse/result[2] immer den zweiten Ergebnis.

Ausdrucktyp
Stammknoten
XPath-Ausdruck: „/
Auswahl:
    <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>
    
absoluter Pfad
XPath-Ausdruck: „/WebServiceResponse/result
Auswahl:
    <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>
    
Pfad mit Platzhalter
XPath-Ausdruck: „/WebServiceResponse//location
Auswahl:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Pfad mit Prädikat
XPath-Ausdruck: „/WebServiceResponse/result[2]/message
Auswahl:
    <message>The secret message</message>
    
Alle direkt untergeordneten Elemente des ersten result
XPath-Ausdruck: „/WebServiceResponse/result[1]/*
Auswahl:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
Die name eines result, deren type-Text „Beispiel“ lautet.
XPath-Ausdruck: „/WebServiceResponse/result[type/text()='sample']/name
Auswahl:
    Sample XML
    

Wichtig: Beim Auswählen von Elementen wählen Sie Knoten aus. und nicht nur den Text innerhalb dieser Objekte. Im Allgemeinen über alle übereinstimmenden Knoten iterieren und den Text extrahieren. Ich kann auch direkt mit Textknoten übereinstimmen. Siehe Textknoten unten.

Beachten Sie, dass XPath auch Attributknoten unterstützt. Allerdings stellen alle Google Maps-Webdienste Elemente ohne Attribute bereit, sodass Abgleich von Attributen ist nicht erforderlich.

Auswahl von Text in Ausdrücken

Text in einem XML-Dokument wird in XPath-Ausdrücken angegeben Textknotenoperator. Der Operator „text()“ zeigt die Extraktion von Text aus dem angegebenen Knoten an. Beispiel: der XPath-Ausdruck „//formatted_address/text()“ Aktion Gesamten Text innerhalb von <formatted_address> zurückgeben Elemente.

Ausdrucktyp
alle Textknoten (einschließlich Leerstellen)
XPath-Ausdruck: „//text()
Auswahl:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Textauswahl
XPath-Ausdruck: „/WebServiceRequest/result[2]/message/text()
Auswahl:
    The secret message
    
Kontextbezogene Auswahl
XPath-Ausdruck: „/WebServiceRequest/result[type/text() = 'sample']/name/text()
Auswahl:
    Sample XML
    

Alternativ können Sie einen Ausdruck auswerten und einen Satz zurückgeben. und iterieren sie dann über diese "Knotengruppe", Extrahieren des Text aus jedem Knoten. Dieser Ansatz wird im Beispiel unten verwendet.

Weitere Informationen zu XPath findest du in der XPath-W3C-Spezifikation

XPath in Java auswerten

Java bietet umfassende Unterstützung für das Parsen von XML und die Verwendung von XPath-Ausdrücken. im javax.xml.xpath.*-Paket. Aus diesem Grund wird im Beispielcode in diesem Abschnitt Java verwendet, veranschaulichen, wie XML verarbeitet und Daten aus XML-Dienstantworten geparst werden.

Um XPath in Ihrem Java-Code zu verwenden, müssen Sie zuerst Instanz eines XPathFactory und rufen Sie newXPath() für diese Factory, um ein XPath -Objekt zu erstellen. Dieses Objekt kann dann übergebene XML-Daten verarbeiten, und XPath-Ausdrücke mit der Methode evaluate().

Achten Sie bei der Auswertung von XPath-Ausdrücken darauf, mögliche „Knotengruppen“ die zurückgegeben werden können. Da diese Ergebnisse als DOM-Knoten im Java-Code zurückgegeben werden, sollten Sie wie mehrere Werte in einem NodeList-Objekt und über dieses Objekt iterieren, um Text oder Werte daraus zu extrahieren Knoten.

Der folgende Code zeigt, wie ein XPath erstellt wird. , weisen Sie ihm XML und einen XPath-Ausdruck zu und werten Sie die um die relevanten Inhalte auszudrucken.

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