Веб-службы Google Maps API

Google Maps Web Services – это коллекция HTTP-интерфейсов к службам Google, предоставляющих географические данные в приложения для работы с картами. В данном руководстве приводится краткая информация о веб-службах и узлах, общих для всех служб. Ниже приведена документация для каждой отдельной службы:

Какой API вам нужен?

Используйте средство выбора API, чтобы найти соответствующий API-интерфейс для своего проекта.

Дополнительная информация о веб-службах

Далее в данном руководстве будут описаны способы построения запросов к веб-службам и синтаксический анализ ответов. Для получения подробной информации о каждой службе см. соответствующую документацию.

Что такое веб-служба?

Google Maps API предоставляет веб-службы в качестве интерфейса для запроса данных Maps API из внешних служб и их использования в приложениях Google Maps. Данные службы предназначены для использования вместе с картой в соответствии с Лицензионные ограничения условий использования Maps API.

В данных веб-службах используются запросы HTTP на определенные URL-адреса, которые передают в службы параметры URL-адреса в виде аргументов. Обычно данные службы возвращают данные в запросе HTTP в формате JSON или XML для выполнения синтаксического анализа и/или обработки с помощью вашего приложения.

Стандартный запрос к веб-службе обычно имеет следующую форму:

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

где service обозначает запрашиваемую службу, а output – это формат ответа (обычно json или xml).

Полная документация по каждой службе приведена в соответствующих руководствах разработчика таких служб. Однако в данном руководстве описываются наиболее распространенные способы построения запросов, отправляемых в веб-службы, и обработки ответов.

Доступ по протоколу SSL

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

Протокол HTTPS требуется для всех запросов к веб-службам Maps API, содержащих пользовательские данные или идентификаторы разработчика. Отправленные по протоколу НТТР запросы, которые содержат чувствительные данные, могут быть отклонены.

Создание допустимого URL-адреса

Вам, возможно, покажется, что понятие "допустимый" URL-адрес очевидно и не нуждается в определении, однако это не совсем так. URL-адрес, введенный в адресную строку браузера, может содержать специальные символы (например, "上海+中國"); перед осуществлением перехода по указанному адресу браузеру необходимо выполнить перевод этих символов в другую кодировку. Аналогичным образом, любой код, которые создает или принимает данные в формате UTF-8, может интерпретировать URL-адреса с символами UTF-8 как "действительные", но ему также потребуется перевести эти символы перед их отправкой на веб-сервер. Этот процесс называется кодированием URL-адреса.

Необходимость перевода символов связана с тем, что все URL-адреса должны соответствовать синтаксису, указанному в спецификации Унифицированного идентификатора ресурсов W3. На практике это значит, что URL-адреса должны содержать только определенный набор символов ASCII: знакомые буквенно-числовые символы и некоторые зарезервированные символы, используемые в качестве управляющих в URL-адресах. Эти символы приведены в следующей таблице:

Список символов, допустимых в URL-адресах
ГруппаСимволыИспользование в URL-адресе
Буквенно-числовые 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 Текстовые строки, схемы (http), порт (8080) и др.
Незарезервированные - _ . ~ Текстовые строки
Зарезервированные ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Управляющие символы и/или текстовые строки

При создании допустимого URL-адреса необходимо убедиться, что в нем содержатся только вышеперечисленные символы. Необходимость соответствия набора символов, используемых в URL-адресе, вызывает две следующие ситуации, когда требуется пропуск или замена символов:

  • Если символы, которые вы хотите использовать, не включены в указанный выше набор. Например, символы на иностранных языках, такие как 上海+中國, должны быть кодированы с помощью приведенных выше символов. Согласно принятым правилам, пробелы (которые запрещены в URL-адресах) часто обозначаются знаком '+'.
  • Если используются символы, которые представлены в указанном выше наборе как зарезервированные, но их нужно использовать как есть, без изменений. Например, символ "?" используется в URL-адресах для обозначения начала строки запроса; если вы хотите использовать строку "? and the Mysterions", вам необходимо закодировать символ "?".

Все символы, которые необходимо закодировать в URL-адресах, кодируются с помощью символа "%" и двухзначного шестнадцатеричного значения, соответствующего символу UTF-8. Например, 上海+中國 в UTF-8 будет закодирован в URL-адресе как %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B. Строка ? and the Mysterians будет закодирована в URL-адресе как %3F+and+the+Mysterians.

Далее приведены распространенные символы, требующие кодировки:

Небезопасные символы Закодированное значение
Пробел %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

Конвертирование URL-адреса, вводимого пользователем, может быть непростой задачей. Рассмотрим пример, когда пользователь вводит адрес "5th&Main St." Обычно URL-адрес необходимо создавать из отдельных частей, обрабатывая все вводимые пользователем данные как символьные литералы.

Как правило, URL-адреса могут содержать не более 8192 символов для всех веб-служб. Для большинства служб это ограничение символов превышается крайне редко. Однако некоторые службы могут содержать ряд параметров, которые могут привести к образованию длинных URL-адресов.

Бережное использование API Google

Плохо спроектированные клиенты API могут сверх необходимости загружать как интернет, так и серверы Google. В этом разделе описываются практические рекомендации для клиентов API. Их применение может помочь избежать блокировки вашего приложения за неумышленное злоупотребление API.

Экспоненциальная задержка

В редких случаях при обработке запроса возможен сбой – вы можете получить код ответа НТТР 4XX или 5XX, либо возможен разрыв соединения TCP где-то между вашим клиентом и сервером Google. Часто стоит просто повторить запрос, поскольку следующий запрос может получить ответ, даже если первоначальный запрос не сработал. Однако, важно не просто зациклить повторяющиеся запросы на серверы Google. Такое зацикливание может перегрузить сеть между вашим клиентом и Google, вызвав затруднения у многих пользователей.

Повторно пробовать лучше с возрастающими задержками между попытками. Обычно задержка с каждой попыткой увеличивается мультипликативным множителем – такой подход известен как экспоненциальная задержка.

Например, рассмотрим приложение, которое хочет сделать такой запрос к Google Maps Time Zone API:

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

Следующий пример на языке Python показывает, как сделать запрос с экспоненциальной задержкой.

import json
import time
import urllib
import urllib2

def timezone(lat, lng, timestamp):
    # 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
    maps_key = 'YOUR_KEY_HERE'
    timezone_base_url = 'https://maps.googleapis.com/maps/api/timezone/json'

    # This joins the parts of the URL together into one string.
    url = timezone_base_url + '?' + urllib.urlencode({
        'location': "%s,%s" % (lat, lng),
        'timestamp': timestamp,
        'key': maps_key,
    })

    current_delay = 0.1  # Set the initial retry delay to 100ms.
    max_delay = 3600  # Set the maximum retry delay to 1 hour.

    while True:
        try:
            # Get the API response.
            response = str(urllib2.urlopen(url).read())
        except IOError:
            pass  # Fall through to the retry loop.
        else:
            # If we didn't get an IOError then parse the result.
            result = json.loads(response.replace('\\n', ''))
            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.

tz = timezone(39.6034810, -119.6822510, 1331161200)
print 'Timezone:', tz

Следует позаботиться о том, чтобы выше в цепи вызовов приложения не было кода повторной попытки, иначе это приведет к повторным запросам в быстрой очередности.

Синхронизированные запросы

Большое количество синхронизированных запросов к API Google могут выглядеть как распределенная атака на отказ в обслуживании (DDoS) на инфраструктуру Google, что вызовет соответствующую реакцию. Чтобы этого избежать, вы должны убедиться, что запросы к API не синхронизированы между клиентами.

Например, рассмотрим приложение, которое показывает время в текущем часовом поясе. Это приложение наверняка может установить будильник в операционной системе клиента, который будит ее в начале минуты, чтобы отображаемое время можно было обновить. Это приложение не должно делать никаких обращений к API в качестве составной части процесса, связанного с таким будильником.

Обращения к API в ответ на фиксированный будильник является недопустимым, поскольку приводит к синхронизации обращений к API по началу минуты, даже между разными устройствами, вместо равномерного распределения по времени. Плохо разработанное приложение, в котором такое происходит, создаст скачок трафика, в шестьдесят раз превышающий нормальный уровень в начале каждой минуты.

Вместо этого, одним из хороших вариантов реализации будет будильник, устанавливаемый в случайно выбранную секунду. Когда срабатывает такой секундный будильник, приложение обращается к любому API, которое ему требуется, и сохраняет результаты. Если приложение хочет обновить экран в начале минуты, оно использует предварительно сохраненные результаты, а не обращается к API снова. При таком подходе, обращения к API равномерно распределяются по времени. Более того, обращения к API не задерживают отображение, когда экран обновляется.

Помимо начала минуты, другими распространенными временными интервалами синхронизации, на которые не следует ориентироваться, являются начало часа и начало суток в полночь.

Обработка ответов

Поскольку не гарантируется точный формат индивидуальных ответов на запросы в веб-службы (некоторые элементы могут отсутствовать или находиться в различных местоположениях), необходимо учитывать, что полученный формат ответа не будет одинаков для различных запросов. Вы должны обработать ответ и выбрать соответствующие значения с помощью выражений. В данном разделе описывается процесс динамического извлечения этих значений из ответов веб-служб.

Веб-службы Google Maps предоставляют простые ответы, которые удобны для понимания, но не всегда удобны в использовании. При отправке запроса, вместо отображения набора данных, вам, вероятно, требуется извлечь несколько конкретных значений. Как правило, необходимо выполнить синтаксический анализ ответов от веб-служб и извлечь только необходимые значения.

Используемая схема синтаксического анализа зависит от формата ответов (XML или JSON). Ответы в формате JSON, которые уже имеют форму объектов Javascript, могут обрабатываться в самом Javascript на клиентском устройстве; ответы в формате XML должны обрабатываться с помощью средства обработки XML, используя язык запросов XML, что позволяет учесть все элементы в рамках этого формата. В следующих примерах используется XPath, так как он обычно поддерживается в библиотеках обработки XML.

Обработка XML с помощью XPath

XML – это хорошо отлаженный формат обработки структурированной информации, используемый для обмена данными. Хотя он имеет не такой малый размер как JSON, XML обеспечивает поддержку большего количества языков и имеет более широкие возможности. Код для обработки XML в Java, например, встроен в пакеты javax.xml.

При обработке ответов XML необходимо использовать соответствующий язык запросов для выбора узлов в документе XML, не рассчитывая на то, что элементы находятся в абсолютных положениях в разметке XML. XPath – это языковой синтаксис, предназначенный для создания уникального описания узлов и элементов в документе XML. Выражения XPath позволяют идентифицировать определенный контент в документе ответа XML.

Выражения XPath

Знакомство с XPath существенно упрощает разработку эффективной схемы синтаксического анализа. В данном разделе описывается процесс работы с элементами в документе XML с помощью XPath, который позволяет одновременно использовать множество элементов и создавать сложные запросы.

XPath использует выражения для выбора элементов в документе XML, применяя синтаксис, аналогичный используемому в путях каталогов. Эти выражения определяют элементы в дереве документа XML, представляющем собой иерархическое дерево, аналогичное дереву DOM. Обычно выражения XPath построены на основе "жадных" алгоритмов и стремятся определить соответствия для всех узлов, удовлетворяющих указанным критериям.

В нашем примере будем использовать следующий фрагмент 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>

Выбор узлов в выражениях

Запросы XPath выбирают узлы. Корневой узел охватывает целый документ. Вы выбираете данный узел с помощью специального выражения "/". Обратите внимание, что корневой узел не является узлом верхнего уровня документа XML; он фактически расположен на один уровень выше элемента верхнего уровня и включает его в себя.

Узлы элементов содержат различные элементы в дереве документа XML. Например, элемент <WebServiceResponse> представляет собой элемент верхнего уровня, возвращенный в нашу службу, описанную выше. Вы выбираете отдельные узлы с помощью абсолютного или относительного пути, обозначенного наличием или отсутствием символа "/" в начале.

  • Абсолютный путь: выражение "/WebServiceResponse/result" выбирает все узлы <result>, являющиеся дочерними узла <WebServiceResponse>. (Обратите внимание, что оба этих элемента уменьшаются от корневого узла "/".)
  • Относительный путь от текущего контекста: выражение "result" будет соответствовать элементам <result> в текущем контексте. Обычно вам не стоит беспокоиться о контексте, поскольку обработка результатов веб-службы осуществляется с помощью одного выражения.

Одно из этих выражений может быть дополнено за счет шаблона пути, обозначенного двойной косой чертой ("//"). Такой подстановочный символ указывает, что этому промежуточному значению пути могут соответствовать ноль или более элементов. Выражение XPath "//formatted_address", например, будет соответствовать всем узлам с таким именем в текущем документе. Выражение //viewport//lat будет соответствовать всем элементам <lat>, для которых параметр <viewport> является родительским.

По умолчанию выражения XPath соответствуют всем элементам. Вы можете ограничить соответствие выражения только определенным элементам, указав предикат, заключенный в квадратные скобки ([]). Например, выражение XPath "/GeocodeResponse/result[2] всегда возвращает второй результат.

Тип выражения
Корневой узел
Выражение XPath:  "/"
Выборка:
    <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>
    
Абсолютный путь
Выражение XPath:  "/WebServiceResponse/result"
Выборка:
    <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>
    
Путь с подстановочным символом
Выражение XPath:  "/WebServiceResponse//location"
Выборка:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Путь с предикатом
Выражение XPath:  "/WebServiceResponse/result[2]/message"
Выборка:
    <message>The secret message</message>
    
Все прямые дочерние элементы первого результата (result)
Выражение XPath:  "/WebServiceResponse/result[1]/*"
Выборка:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
Имя (name) результата (result), тип (type) текста которого совпадает с "sample".
Выражение XPath:  "/WebServiceResponse/result[type/text()='sample']/name"
Выборка:
    Sample XML
    

Важно отметить, что при выборе элементов происходит выбор самих узлов, а не просто текста в объектах. Как правило, необходимо выполнить итерацию по всем совпавшим узлам и извлечь этот текст. Также можно найти прямое соответствие текста в узлах; см. про Текстовые узлы ниже.

Обратите внимание, что XPath также поддерживает узлы с атрибутами, однако веб-службы Google Maps обрабатывают элементы без атрибутов, поэтому сопоставление атрибутов не требуется.

Выборка текста в выражениях

Текст в документе XML указывается в выражениях XPath с помощью оператора текстового узла. Данный оператор "text()" запрашивает извлечение текста из указанного узла. Например, выражение XPath "//formatted_address/text()" вернет весь текст в элементах <formatted_address>.

Тип выражения
Все текстовые узлы (включая пробелы)
Выражение XPath:  "//text()"
Выборка:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Выборка текста
Выражение XPath:  "/WebServiceRequest/result[2]/message/text()"
Выборка:
    The secret message
    
Чувствительная к контексту выборка
Выражение XPath:  "/WebServiceRequest/result[type/text() = 'sample']/name/text()"
Выборка:
    Sample XML
    

Вы также можете оценить выражение и вернуть набор узлов, а затем выполнить итерации по всем узлам этого набора, извлекая из каждого текст. Данный способ показан в примере ниже.

Дополнительную информацию об XPath см. в документе Характеристики W3C XPath.

Выполнение оценки XPath в Java

В языке Java предусмотрена всесторонняя поддержка синтаксического анализа XML и использования выражений XPath в пакете javax.xml.xpath.*. Поэтому в примере кода в данном разделе для иллюстрации процесса работы с XML и выполнения синтаксического анализа данных, полученных в ответах службы XML, используется язык Java.

Для использования XPath в коде Java сначала необходимо создать объект XPathFactory и вызвать метод newXPath() в этой фабрике для получения объекта XPath. После этого данный объект сможет обрабатывать переданные выражения XML и XPath, используя метод evaluate().

При оценке выражений XPath убедитесь, что выполняется итерация по всем наборам узлов, которые могут быть возвращены. Поскольку результаты возвращаются как узлы DOM в коде Java, необходимо выполнить захват этого множества значений в объект NodeList и осуществить итерации по этому объекту, извлекая текст или значения из полученных узлов.

В следующем коде показан процесс создания объекта XPath, назначение XML и выражения XPath, а также оценка выражения для выведения соответствующего контента.

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

Загрузите код из js-v2-samples

Обработка JSON с помощью Javascript

JSON (Javascript Object Notation) имеет очевидное преимущество перед XML, заключающееся в малом размере ответа. Синтаксический анализ такого результата в JavaScript не представляет проблем, поскольку его формат уже является допустимым объектом Javascript. Например, для извлечения значения ключей "formatted_address" в объекте результата JSON просто запросите их с помощью следующего кода:

for (i = 0; i < myJSONResult.results.length; i++) {
  myAddress[i] = myJSONResult.results[i].formatted_address;
}

Обратите внимание, поскольку JSON может содержать несколько значений, будет правильнее выполнить несколько итераций по всему массиву results для захвата всех возможных значений. Но на практике может требоваться только первый результат (results[0]).

Синтаксический анализ JSON в других языках может быть не намного сложнее. Следующий пример в Python инициирует запрос в веб-службу Geocoding и отображает пользователю все полученные значения formatted_address в массиве:

import simplejson, urllib

GEOCODE_BASE_URL = 'https://maps.googleapis.com/maps/api/geocode/json'

def geocode(address, **geo_args):
    geo_args.update({
        'address': address
    })

    url = GEOCODE_BASE_URL + '?' + urllib.urlencode(geo_args)
    result = simplejson.load(urllib.urlopen(url))

    print simplejson.dumps([s['formatted_address'] for s in result['results']], indent=2)

if __name__ == '__main__':
    geocode(address="San+Francisco")

Output: [ "San Francisco, CA, USA" ]

Загрузите код из js-v2-samples

Параметр sensor

Ранее запросы Google Maps API обязательно должны были содержать параметр sensor, чтобы указать, использовался ли приложением датчик для определения местоположения пользователя. Этот параметр больше не используется.

Оставить отзыв о...

Текущей странице
Интерфейсы Google Maps Web Service API
Интерфейсы Google Maps Web Service API