Сетевое взаимодействие
Врезка: Имитация сетей с лимитным тарифным планом
Вы можете подумать: "Хорошо, я реализую в своем приложении правильное поведение в сетях с лимитным тарифным планам, но как мне все это проверить, не тратя кучу денег на оплату счетов операторов (включая плату за роуминг)?". Простой ответ заключается в том, что вы можете имитировать поведение сети с лимитным танифным планом с помощью любого Wi-Fi-соединения. Во-первых, откройте интерфейс чудо-кнопки Параметры и щелкните по значку вашего сетевого соединения, расположенного около ее нижней части (смотрите верхний левый рисунок, в особенности – верхний левый значок, который имеет подпись "Nuthatch"). В панели Сети (Networks), которая после этого откроется (нижнее правое изображение), щелкните правой кнопкой мыши по беспроводному соединению и выберите параметр Задать как лимитное подключение (Set As Metered Connection):
Хотя включение этого параметра не установит свойства DataUsage и все те сведения, которые можно получить в реальной лимитированной сети, но благодаря ему networkCostType будет установлено в значение fixed, что позволяет вам увидеть, как отреагирует на это ваше приложение. Так же вы можете воспользоваться элементом меню Показать оценочные сведения об использовании данных (Show Estimated Data Usage) для того, чтобы увидеть, какой трафик генерирует ваше приложение при нормальной работе, и вы можете сбросить счетчик для того, чтобы получить более точные показания:
Работа без подключения к сети
Другая возможность, которая, несомненно, позволит улучшить репутацию вашего приложения, это то, как оно ведет себя, когда отсутствует подключение к сети или подключение изменяется. Задайте себе следующие вопросы:
- Что происходит, если ваше приложение запускается при отсутствии сетевого соединения, и с плитки (основной и дополнительной) и посредством контракта, такого, как контракт Поиск, Общий доступ, контракт средства выбора файлов?
- Что происходит, если ваше приложение запускается в первый раз, а сетевого соединения нет?
- Что происходит при потере сетевого соединения во время выполнения вашего приложения?
- Что происходит, когда соединение восстанавливается?
Как описно выше, в разделе "Сведения о стоимости передачи данных", вы можете использовать событие networkstatuschanged для обработки таких ситуаций при исполнении приложения и обработчик resuming для проверки изменения состояния соединения, которое могло произойти пока приложение было приостановлено. Если у вас есть фоновая задача, связанная с триггером networkStateChange, вам сначала нужно сохранить сведения о состоянии, которые сможет проверить ваш обработчик resuming
Отлично понятно, что некоторые приложения попросту не смогут запуститься при отсутствии сетевого соединения, и в таком случае нужно оповестить пользователя об этой ситуации, когда приложение запускается при отсутствии соединения, или когда соединение пропадает в ходе работы приложения. В других ситуациях приложение может быть частично функционирующим, при этом вы так же должны сообщить об этом пользователю, на индивидуальной основе, позволив ему пользоваться теми частями приложения, функциональность которых это не затрагивает. Лучше всего осуществлять кэширование данных, что может сделать приложение гораздо более полезным при потере соединения. Важные данные так же могут быть встроенные в пакет приложения, таким образом, они всегда будут доступны при первом запуске.
Представьте себе ситуацию с приложением для чтения электронных книг, которое обычно получает новые материалы из онлайнового каталога. Для пользователей, работающих без подключения к сети, хорошо будет кэшировать их материалы локально, вместо того, чтобы полагаться только на Интернет-соединение. Издатель приложения может так же включить некоторое количество популярных изданий прямо в пакет приложения, таким образом, пользователь может установить приложение в ожидании рейса в аэропорту, и у него будут, как минимум, эти книги, когда приложение впервые будет запущено на высоте в 30000 футов. Другие приложения могут включать некоторый набор предусстановленных данных, доступных при первом запуске и затем добавлять новые данные (возможно, посредством покупок внутри приложения), когда доступно неограниченное сетевое соединение. Учитывая стоимость лимитированного сетевого соединения, подобное приложение может отложить загрузку большого объема данных либо до получения подтверждения пользователя на эту операцию, либо при доступности другого подключения
Как и когда кэшировать данные из онлайновых источников, это один из вопросов, ответ на который требует большого искусства от разработчика программного обеспечения. Когда загружать данные? Сколько данных загружать? Где их хранить? Следует ли задать верхнее ограничение на размер кэша? Позволить ли изменять кэшированные данные, что вызовет необходимость синхронизации с сервером, когда соединение будет восстановлено? Это отличные вопросы, но есть, конечно, и другие. Позвольте мне, по крайней мере, предложить несколько идей и предложений.
Во-первых, вы можете использовать любой сетевой транспорт для того, чтобы загрузить данные для кэширования, такой, как WinJS.xhr, API фоновой передачи данных, а так же механизмом HTML5 AppCache (http://msdn.microsoft.com/library/ie/hh673545.aspx), который хорошо подходит для веб-содержимого, которое вы загружаете в элементы iframe. Обратите внимание на то, что использование AppCache требует, чтобы URI, имеющие дело к вопросу, были объявлены в манифесте, как ApplicationContentUri (URI содержимого) (смотрите Главу 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript"). В свою очереть, другие данные, полученные из удаленных источников, такие, как изображения, кэшируются автоматически, как временные файлы Интернета. Даже удаленный скрипт, загруженный в iframe, работающий в веб-контексте, кэшируется подобным образом. И механизмы кэширования, и вопрос об ограничениях размера кэша задает Internet Explorer.
Сколько данных хранить в кэше, зависит, конечно, от типа соединения и сравнительной важности данных. В безлимитных сетях, можете загружать все, что может понадобиться пользователю в оффлайновом режиме, но хорошо будет представить настройки для управления этим процессом, такие, как общий размер кэша или объем данных, которые можно получать ежедневно. Я упомянул это, так как, хотя мое интернет-соединение выглядит для системы как безлимитное, я плачу больше, когда использование трафика достигает определенных пределов (речь идет о гигабайтах). Как пользователь, я был бы признателен за право голоса в вопросах, которые касаются большого потребления сетевого трафика.
Тем не менее, если кэширование каких-либо данных серьезно расширит возможности по работе с приложением, выделите эти параметры для того, чтобы позволить пользователю принимать решения. Например, программа для чтения электронных книг может автоматически загружать всю книгу, когда читатель, возможно, лишь просматривает первые несколько страниц. Конечно, это так же означает потребление большего дискового пространства. Позвольте пользователям контролировать это поведение посредством параметров, или даже для каждой книги, позвольте им самим решить, что им лучше подходит. С другой стороны, для данных небольшого объема, скажем, в пределах нескольких сотен килобайт, если вы знаете из аналитики, что пользователь, который просмотрел некий набор данных, весьма вероятно обратится и к другим данным, автоматическая загрузка и кэширование подобных дополнительных наборов данных может быть признана правильным подходом.
Лучшее место для хранения кэшированных данных, это папки данных вашего приложения, в особенности, LocalFolder и TemporaryFolder. Избегайте использования RoamingFolder для кэширования данных, полученных из онлайновых источников: помимо риска превысить ограничение на объем перемещаемых данных (смотрите Главу 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript"), это еще и не имеет особого смысла. Так как система будет, в любом случае, перемещать эти данные по сети, лучше позволить приложению снова их загрузить, когда ему это будет нужно. То же самое касается и покупок внутри приложения: так как пользователь может легко загрузить эти покупки из Магазина Windows на другое устройство (и приложение на этом устройстве обнаружит, что данные покупки уже оплачены), перемещать их между устройствами не нужно.
Использовать ли LocalFolder или TemporaryFolder, зависит от того, насколько важны данные в работе приложения. Если приложение не может запуститься без кэша – как, например, приложение с рецептами, которое я раньше упоминал – используйте папку локальных данных приложения. Если кэш – это лишь оптимизация и пользователь может очистить занятое им пространство с помощью средства очистки диска, сохраните его в TemporaryFolder и снова восстановите позже. (Хочу еще раз напомнить, что IndexedDB, как описано в Главе 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript", имеет ограничение на объем данных, который может хранить приложение и общий системный лимит. Если это – потенциальный источник проблем, вы можете воспользоваться другим механизмом хранения данных.
При всем этом, так же учтите, что то, что вы кэшируете, на самом деле может быть пользовательскими данными, которые хранятся за пределами папок данных приложения. То есть, не забудьте подумать о различиях между данными приложения и пользовательскими данными!
И, наконец, есть приложения, которые позволяют пользователю работать без подключения к сети (например, обрабатывать почту), при этом вы кэшируете результат этой деятельности для последующей синхронизации с онлайновым ресурсом. Когда соединение восстановлено, проверьте, все ли в порядке со стоимостью соединения, прежде чем начинать синхронизацию.
Врезка: Сетевое соединение и изображения из удаленных источниках на динамических плитках и всплывающих уведомлениях
В Главе 2 мы говорили о том, как приложение может выглядеть динамичным, выполняющим какие-то действия, посредством таких возможностей, как динамические плитки и уведомления. Очевидно, периодические уведомления и push-уведомления полностью зависят от состояния соединения и без него работать не будут. Исполняющееся приложение, с другой стороны, может отправлять обновление при отсутствии подключения. В подобных обстоятельствах приложению следует избегать ссылаться на удаленные изображения в обновления, так как они не смогут быть загружены при отсутствии соединения, а системы поддержки плиток и всплывающих уведомлений сейчас не поддерживают использование локальных резервных копий изображений. Таким образом, приложению следует проверить состояние соединения перед отправкой обновления и при его отсутствии использовать локальные (ms-appx:/// или ms-appdata:///) изображения вместо удаленных или использовать шаблоны плиток и уведомлений, которые содержат только текст.
XmlHttpRequest
Как мы уже много раз видели, передача данных на веб-сервис и с него с использованием XmlHttpRequest, это вполне обычное дело для приложений для Магазина Windows, особенно для тех, которые написаны на JavaScript, для которых обработка XML и/или JSON весьма проста. Это особенно справедливо при использовании оболочки WinJS.xhr, которая превращает весь процесс в обычный promise-вызов.
Для того, чтобы пользоваться тем, что мы уже рассматривали в Главе 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", нужно учесть еще несколько особенностей, связанных с подобными запросами, большинство из которых описаны в материале "Подключение к веб-службам" (http://msdn.microsoft.com/library/windows/apps/hh761502.aspx).
Во-первых, материал "Загрузка различных типов содержимого" (http://msdn.microsoft.com/library/windows/apps/hh868280.aspx) содержит подробности о различных типах содержимого, которые поддерживает XHR для приложений Магазина. Основные сведения о них приведены здесь:
Тип | Использование | responseText | responseXML |
---|---|---|---|
arraybuffer | Двоичное содержимое, массив Int8 или Int64, или других целочисленных типов и типов с плавающей запятой. | Неопределено | Неопределено |
Blob | Двоичное содержимое, представленное в виде единого объекта. | Неопределено | Неопределено |
document | Объект XML DOM представленный XML-содержимым (MIME –тип text/XML). | Неопределено | XML -содержимое |
json | JSON-строки. | Строка JSON | Неопределено |
ms-stream | Потоковые данные;смотрите материал "Улучшения объекта XMLHttpRequest" (http://msdn.microsoft.com/library/windows/apps/hh673569.aspx) | Неопределено | Неопределено |
Text | Текст (по умолчанию). | Текстовая строка | Неопределено |
Вот-вторых, знайте, что XHR-ответы могут быть автоматически кэшированы, что подразумевает то, что более поздние запросы по тому же URI могут привести к возврату устаревших данных. Для того, чтобы повторно отправить запрос без учета кэша, добавьте HTTP-заголовок If-Modified-Since так, как показано в материале "Проверка отправки повторных запросов с помощью WinJS.xhr" (http://msdn.microsoft.com/library/windows/apps/hh868281.aspx).
Рассуждая в том же русле, вы можете заключить операцию WinJS.xhr в другой promise-объект для того, чтобы реализовать автоматические повторы при возникновении ошибки в любом заданном запросе. Таким образом, построить логику повторных запросов вокруг операции XHR с сохранением результата в некоторой переменной. Потом поместите весь код в WinJS.Promise.wrap (или в новый WinJS.Promise) и используйте это везде, где нужно, в приложении.
В каждой попытке выполнения запроса с помощью XHR помните, что вы так же можете использовать WinJS.Promise.timeout вместе с WinJS.Xhr , как описано в материале "Установка значений времени ожидания с помощью WinJS.xhr" (http://msdn.microsoft.com/library/windows/apps/hh868283.aspx), так как в WinJS.xhr нет прямого описания тайм-аутов. Вы можете, конечно, установить время ожидания в необработанном запросе, но это означает создание зонного всего того, что уже есть в WinJS.xhr.
Вообще говоря, XHR-заголовки доступны приложению, за исключением куки (заголовки set-cookie и set-cookie2), так как они отфильтрованы при использовании XHR в локальном контексте. Они не отфильтрованы для XHR, который работает в веб-контексте, поэтому, если вам нужны куки, попытайтесь получить их элементе iframe, который работает в веб-контексте, и передать в локальный контекст с использованием postMessage.
Наконец, избегайте использования XHR для передачи больших файлов, так как подобные операции будут приостанавливаться при приостановке работы приложений. Вместо этого используйте API фоновой передачи данных (смотрите следующий раздел), который использует возможности XHR, в итоге, ваш веб-сервис не увидит никакой разницы!
И на этой ноте давайте посмотрим на то, как устроен API фоновой передачи данных.
Врезка: отладка передачи данных по сети с помощью Fiddler
Если вы заинтересованы в просмотре HTTP(S)-трафика между вашим компьютером и интернетом, что прямо-таки неоценимо при работе с XmlHttpRequests—взгляните на бесплатный инструмента, известный как Fiddler (http://www.fiddler2.com/fiddler2/). В дополнение к проверке трафика, вы так же можете устанавливать точки останова на различные события и "рыться" во входящих и исходящих данных (то есть, изменять их). Этот сервис поддерживает трафик от любого приложения или браузера, в том числе – и от приложений для Магазина Windows.