Prácticas recomendadas para usar los servicios web de la API de Distance Matrix

Los servicios web de Google Maps Platform son un conjunto de interfaces HTTP para que proporcionan datos geográficos a tus aplicaciones de mapas.

En esta guía, se describen algunas prácticas comunes que sirven servicio web las solicitudes y el procesamiento de las respuestas del servicio. Consulta la guía para desarrolladores. para obtener la documentación completa de la API de Distance Matrix.

¿Qué es un servicio web?

Los servicios web de Google Maps Platform son una interfaz para solicitar datos de la API de Google Maps a servicios externos y el uso de los datos en sus aplicaciones de Maps. Estos servicios son diseñado para usarse junto con un mapa, según el Restricciones de licencia en las Condiciones del Servicio de Google Maps Platform.

Los servicios web de las APIs de Google Maps usan solicitudes HTTP(S) para URLs específicas y pasan parámetros de URL, Datos POST en formato JSON como argumentos para los servicios. Generalmente, estos servicios devuelven datos en el de respuesta como JSON o XML para analizarlos y/o procesamiento por parte de tu aplicación.

Una solicitud típica a la API de Distance Matrix tiene el siguiente formulario:

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

donde output indica el formato de la respuesta (por lo general, json o xml).

Nota: Todas las aplicaciones de la API de Distance Matrix requieren autenticación. Obtén más información sobre las credenciales de autenticación.

Acceso SSL/TLS

Se requiere HTTPS para todas las solicitudes de Google Maps Platform que usan claves de API o contienen información de datos no estructurados. Es posible que se rechacen las solicitudes realizadas a través de HTTP que contengan datos sensibles.

Cómo crear una URL válida

Tal vez creas que una dirección URL "válida" es evidente, pero no siempre es así. Una URL que se ingresa en una barra de direcciones en un navegador, por ejemplo, puede contener caracteres especiales (p. ej., "上海+中國"), y el navegador debe traducir internamente esos caracteres a una codificación diferente antes de la transmisión. Con el mismo token, cualquier código que genere o acepte entradas en UTF-8 podría procesar las URLs con caracteres UTF-8 como "válidas", pero también necesitaría traducir esos caracteres antes de enviarlos a un servidor web. Este proceso se llama codificación de URLs o codificación por ciento.

Caracteres especiales

Debemos traducir los caracteres especiales porque todas las URLs deben cumplir con los requisitos de sintaxis que se indican en la especificación Identificador de recursos uniformes (URI). En efecto, esto significa que las URLs deben contener solo un subconjunto especial de caracteres ASCII: los símbolos alfanuméricos que ya conocemos y algunos caracteres reservados para usar como caracteres de control en las URLs, los cuales se resumen en la siguiente tabla:

Resumen de caracteres válidos para URLs
ConjuntocaracteresUso en la URL
Alfanuméricos 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 Cadenas de texto, uso de esquemas (http), puerto (8080), etcétera
No reservados - _ . ~ Cadenas de texto
Reservados ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Caracteres de control o cadenas de texto

Al crear una URL válida, debes asegurarte de que contenga solo los caracteres que se muestran en el desde una tabla de particiones. Adaptar una dirección URL para usar este conjunto de caracteres generalmente provoca dos problemas, de omisión y de sustitución:

  • Quizá quieras usar caracteres que no se encuentran dentro del conjunto anterior. Por ejemplo, los caracteres de otros idiomas, como 上海+中國, deben codificarse con los caracteres que se indican arriba. Por convención popular, los espacios (que no se permiten en las URLs) suelen representarse también con el carácter de signo más '+'.
  • Hay caracteres dentro del conjunto anterior que son caracteres reservados, pero se deben usar literalmente. Por ejemplo, ? se usa en las URLs para indicar el comienzo de la cadena de consulta; si deseas utilizar la cadena "? and the Mysterions", debes codificar el carácter '?'.

La codificación de caracteres para URLs usa un carácter '%' y un valor hexadecimal de dos caracteres correspondiente a su carácter en UTF-8. Por ejemplo, 上海+中國 en UTF-8 se codificaría como %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B para usarse en URLs. La cadena ? and the Mysterians se codificaría como %3F+and+the+Mysterians o %3F%20and%20the%20Mysterians para usarse en URLs.

Caracteres comunes que necesitan codificación

A continuación se indican algunos de los caracteres que se deben codificar:

Caracteres no seguros Valor codificado
Espacio %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

Convertir una dirección URL que recibes a través de la entrada de un usuario puede ser engañoso. Por ejemplo, un usuario puede ingresar la dirección "5th&Main St.". Generalmente, deberías crear tu URL a partir de sus partes y tratar las entradas del usuario como caracteres literales.

Además, las URLs tienen una limitación de 16,384 caracteres en todos los servicios web y las APIs web estáticas de Google Maps Platform. Para la mayoría de los servicios, este límite de caracteres rara vez se alcanza. No obstante, ten en cuenta que algunos servicios tienen varios parámetros que podrían generar URLs extensas.

Uso normal de las API de Google

Los clientes de API mal diseñados pueden cargar más carga de la necesaria tanto en Internet como en los servidores de Google. En esta sección se explican algunas de las prácticas recomendadas para los clientes de las API. Siguiendo estas prácticas recomendadas pueden ayudarte a evitar que tu aplicación se bloquee por abuso involuntario de las APIs.

Interrupción exponencial

En casos excepcionales, podría producirse un error al procesar tu solicitud. podrías recibir una solicitud HTTP 4XX código de respuesta o la conexión TCP puede fallar en algún lugar entre tu cliente y la red servidor. A menudo, vale la pena volver a realizar la solicitud, ya que la solicitud de seguimiento puede completarse con éxito si falla la original. Sin embargo, es importante no limitarse repetir indefinidamente solicitudes a los servidores de Google. Este comportamiento de bucle puede sobrecargar entre su cliente y Google causando problemas a muchas partes.

Un mejor enfoque consiste en realizar nuevos intentos con demoras más prolongadas entre uno y otro. Por lo general, el la demora aumenta por un factor multiplicativo con cada intento. Un enfoque conocido como Retirada exponencial.

Por ejemplo, piensa en una aplicación que desee realizar esta solicitud a la API de Time Zone:

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

En el siguiente ejemplo de Python se muestra la manera de realizar la solicitud con interrupción exponencial:

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

También debes tener cuidado de que no haya un código de reintento más alto en la llamada a la aplicación. que genera solicitudes repetidas en sucesión rápida.

Solicitudes sincronizadas

Grandes cantidades de solicitudes sincronizadas a las APIs de Google pueden parecer una infraestructura ataque de denegación del servicio (DDoS) en la infraestructura de Google, y se lo tratará según corresponda. Para evitar esto, debe asegurarse de que las solicitudes a la API no se sincronicen entre los clientes.

Por ejemplo, considera una aplicación que muestre la hora en la zona horaria actual. Esta aplicación probablemente configurará una alarma en el sistema operativo del cliente cuando la active a las el inicio del minuto para que se pueda actualizar la hora que se muestra. La aplicación debe No realizará ninguna llamada a la API como parte del procesamiento asociado con esa alarma.

Es malo realizar llamadas a la API en respuesta a una alarma fija, ya que esto hace que las llamadas a la API se sincronizada al inicio del minuto, incluso entre distintos dispositivos, en lugar de distribuida de manera uniforme con el tiempo. Una aplicación mal diseñada que hace esto producirá un aumento repentino de a 60 veces los niveles normales al comienzo de cada minuto.

En su lugar, un posible buen diseño es tener una segunda alarma configurada en una hora elegida al azar. Cuando esta segunda alarma se activa, la aplicación llama a cualquier API que necesite y almacena la resultados. Cuando la aplicación quiere actualizar su pantalla al inicio del minuto, usa en lugar de volver a llamar a la API. Con este enfoque, las llamadas a la API se distribuyen uniformemente con el tiempo. Además, las llamadas a la API no retrasan la renderización cuando la pantalla se se están actualizando.

Se deben tener cuidado con otros tiempos de sincronización comunes, además del inicio del minuto. no para segmentar son al inicio de una hora y al inicio de cada día a la medianoche.

Procesamiento de respuestas

En esta sección se discute cómo extraer esos valores de forma dinámica de las respuestas de los servicios web.

Los servicios web de Google Maps proporcionan respuestas fáciles de entender, pero no exactamente fácil de usar. Cuando se realiza una consulta, en lugar que mostrar un conjunto de datos, quizás quieras extraer algunos de salida. En general, se recomienda analizar las respuestas de la Web servicio y extraer solo los valores que te interesen.

El esquema de análisis que uses dependerá de si devuelves salida en XML o JSON. Respuestas JSON que ya tienen la forma de Objetos de JavaScript, pueden procesarse dentro del mismo JavaScript en el cliente. Las respuestas XML se deben procesar con un procesador XML y un lenguaje de consulta XML para abordar elementos en formato XML. Usamos XPath en la a continuación, ya que se suele admitir en el procesamiento XML bibliotecas.

Procesamiento de XML con XPath

XML es un formato de información estructurada relativamente maduro que se usa para el intercambio de datos. Aunque no es tan ligero como JSON, XML proporciona compatibilidad de idiomas y herramientas más sólidas. Código para XML en Java, por ejemplo, está integrado en el javax.xml de paquetes.

Al procesar respuestas XML, debes usar un lenguaje de consulta para seleccionar nodos dentro del documento XML, en lugar que suponer que los elementos residen en posiciones absolutas dentro del Lenguaje de marcado XML XPath es una sintaxis de lenguaje para describir nodos y elementos de forma única dentro de un documento XML. Las expresiones XPath te permiten identificar contenido específico dentro del documento de respuesta XML.

Expresiones XPath

Estar familiarizados con XPath ayuda mucho a desarrollar un esquema de análisis sólido. Esta sección se centrará en cómo los elementos en un documento XML se abordan con XPath, lo que te permite abordar múltiples elementos y construir consultas complejas.

XPath usa expresiones para seleccionar elementos en un archivo XML con una sintaxis similar a la que se usa para las rutas de acceso a directorios. Estas expresiones identifican elementos dentro de un documento XML que es un árbol jerárquico similar al de un DOM. Por lo general, las expresiones XPath son codiciosas, lo que indica que coincidirá con todos los nodos que coincidan con los criterios indicados.

Usaremos el siguiente XML abstracto para ilustrar nuestro ejemplos:

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

Selección de nodos en expresiones

Las selecciones de XPath seleccionan los nodos. El nodo raíz que abarque todo el documento. Seleccionas este nodo con la expresión especial "/". Ten en cuenta que la raíz no sea el nodo de nivel superior de tu documento XML. en realidad, reside un nivel por encima de este elemento de nivel superior e incluye que la modifica.

Los nodos de los elementos representan los diversos elementos dentro del archivo XML en el árbol de documentos. Un elemento <WebServiceResponse> por ejemplo, representa el elemento de nivel superior devuelto en nuestra ejemplo anterior. Puedes seleccionar nodos individuales mediante absolutas o relativas, indicadas por la presencia o ausencia de "/" al principio carácter.

  • Ruta de acceso absoluta: "/WebServiceResponse/result" de datos de muestra selecciona todos los nodos <result> que son hijos de <WebServiceResponse> el nodo de inicio de sesión. (ten en cuenta que ambos elementos descienden de la raíz nodo "/").
  • Ruta de acceso relativa a partir del contexto actual: la expresión “result” coincidiría con cualquier <result> dentro del contexto actual. En general, no deberías debes preocuparte por el contexto, ya que, por lo general, procesas datos web servicio a través de una sola expresión.

Cualquiera de estas expresiones puede aumentarse mediante la suma de una ruta de acceso comodín, que se indica con doble barra diagonal (“//”). Este comodín indica que cero o más elementos pueden coincidir en el de la ruta intermediaria. La expresión de XPath "//formatted_address", por ejemplo, coincidirá con todos los nodos que tengan ese nombre en el documento actual. La expresión //viewport//lat coincidiría con todo Elementos <lat> que pueden rastrear <viewport> como padre o madre.

De forma predeterminada, las expresiones Xpath coinciden con todos los elementos. Puedes restringir que la expresión coincida con un elemento determinado mediante un predicado, que está encerrado entre corchetes ([]). La XPath la expresión "/GeocodeResponse/result[2] siempre muestra el segundo resultado, por ejemplo.

Tipo de expresión
Nodo raíz
Expresión de XPath: "/"
Selección:
    <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>
    
Ruta de acceso absoluta
Expresión de XPath: "/WebServiceResponse/result"
Selección:
    <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>
    
Ruta de acceso con comodín
Expresión de XPath: "/WebServiceResponse//location"
Selección:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Ruta de acceso con predicado
Expresión de XPath: "/WebServiceResponse/result[2]/message"
Selección:
    <message>The secret message</message>
    
Todos los elementos secundarios directos de los primeros result
Expresión de XPath: "/WebServiceResponse/result[1]/*"
Selección:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
El name de un result cuyo texto type es "muestra".
Expresión de XPath: "/WebServiceResponse/result[type/text()='sample']/name"
Selección:
    Sample XML
    

Es importante tener en cuenta que al seleccionar elementos, selecciona nodos, no solo el texto dentro de esos objetos. Por lo general, querrá iterar en todos los nodos coincidentes y extraer el texto. Tú también puede hacer coincidir los nodos de texto directamente; consulta Nodos de texto a continuación.

Ten en cuenta que XPath también admite nodos de atributo: Sin embargo, todos los servicios web de Google Maps muestran elementos sin atributos. la coincidencia de atributos no es necesaria.

Selección de texto en expresiones

El texto de un documento XML se especifica en expresiones XPath. con un operador de nodo de texto. El operador "text()" indica la extracción de texto del nodo indicado. Por ejemplo: la expresión de XPath "//formatted_address/text()" la mostrar todo el texto dentro de <formatted_address> o de terceros.

Tipo de expresión
Todos los nodos de tecto (incluidos espacios en blanco)
Expresión de XPath: "//text()"
Selección:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Selección de texto
Expresión de XPath: "/WebServiceRequest/result[2]/message/text()"
Selección:
    The secret message
    
Selección dependiente del contexto
Expresión de XPath: "/WebServiceRequest/result[type/text() = 'sample']/name/text()"
Selección:
    Sample XML
    

Como alternativa, puedes evaluar una expresión y mostrar un conjunto de nodos y luego iterar sobre ese “conjunto de nodos” extrayendo el texto de cada nodo. En el siguiente ejemplo usamos este enfoque.

Para obtener más información sobre XPath, consulta la Especificación W3C de XPath.

Cómo evaluar XPath en Java

Java ofrece una amplia compatibilidad para analizar XML y usar expresiones XPath dentro del paquete javax.xml.xpath.*. Por esa razón, el código de muestra en esta sección usa Java para ilustran cómo manejar XML y analizar datos a partir de respuestas del servicio XML.

Para usar XPath en tu código Java, primero debes crear una instancia una instancia de XPathFactory y llama newXPath() en esa fábrica para crear un objeto XPath Luego, este objeto podrá procesar los archivos XML pasados y XPath con el método evaluate().

Cuando evalúes expresiones XPath, asegúrate de iterar sobre cualquier “conjunto de nodos” posible que puede devolverse. Debido a que estos los resultados se devuelven como nodos DOM en código Java, debes capturar como valores múltiples en un objeto NodeList iterar sobre ese objeto para extraer texto o valores de esos nodos.

En el siguiente código, se muestra cómo crear un XPath objeto, asígnale XML y una expresión XPath, y evalúa la para imprimir el contenido relevante.

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