Приложения для Facebook могут иметь разнообразный функционал: например, часто приложению будет достаточно информации, полученной через API, во время работы пользователя с приложением. Но что делать, если ваше приложение должно работать с самыми “свежими” данными пользователе, даже если они не открывали его уже больше месяца?
Есть два способа для того, чтобы получать данные не только во время работы пользователя с приложением:
Под катом вы узнаете виртуальный пример, как использование real-time updates помогает сократить за день количество запросов к API более чем в 100 раз в некоторых ситуациях. Мы напишем скрипт подписки на обновления и проверим его работу, получив данные о изменении объектов от самого Facebook.
В начале статьи содержится много теории, которая похожа на русский перевод страницы документации с Facebook. Если вам проще читать на английском — вы можете пропустить все во Втором способе до раздела Пример работы Real-Time Updates. Но мне после первого прочтения настроить данный функционал почему-то не удалось. Надеюсь эта статья вам поможет быстрее разобраться в этом.
Функционал некоторых приложений может быть связан с необходимостью получать данные по расписанию. Например, вы собираете статистику количества лайков страниц из определенного каталога. Для этого вы получаете данные с периодичностью раз в час. Это правильный пример использования, по другому вы эти данные просто не получите. Но часто этот способ применяют и для объектов, по которым обновления можно получать не “по расписанию” а real-time от самого Facebook.
Из серьезных недостатков первого способа можно выделить следующие:
Представьте что вы сделали приложение, функционал которого завязан на друзьях пользователя, и вам очень важно иметь самую свежую информацию. Допустим ваше приложение установили 1000 пользователей. И пусть приемлемым временем кеширования данных о друзьях будет 1 час. В итоге каждый день вы будете отправлять 24000 запросов для того, чтобы ваша база данных о друзьях пользователя была актуальна! А у вас всего 1000 пользователей, и можно предположить, что изменений в друзьях на всех за день будет не больше пары сотен (ну это догадка, основанная на личном опыте).
Чтобы решить недостатки первого способа, Facebook сделал Real-Time Updates для своего Graph API.
Поддержка обновлений в реальном времени позволяет вашему приложению подписаться на изменения в данных в Facebook. Ваше приложение получает обновления от Facebook и сохраняет данные, вместо того, чтобы опрашивать серверы Facebook “по расписанию”. Кэширование данных и использование этого API могут улучшить надежность приложения и уменьшить его время загрузки. Всякий раз, когда происходит изменение на которое вы подписаны, Facebook делает HTTP POST запрос к скрипту обработки обновлений данных со списком изменений. Сервер пошлет вам уведомление об изменении в течение пары минут после его появления.
На данный момент вы можете подписаться на следующие типы объектов:
* Не на все свойства и связи объекта User вы сможете подписаться. Например, вам доступны связи: feed, friends, activities, interests, music, books, movies, television, likes, checkins. Но при этом подписаться на изменения этих связей вы пока не сможете: home, tagged, posts, photos, albums, videos, groups, notes, events, inbox, outbox, updates, accounts
Для того, чтобы настроить подписку на обновления, вам нужно:
Отправив запрос на
В запрос должен быть включен access_token приложения, который можно получить, используя ID вашего приложения (app-id) и секретный ключ приложения (app-secret). Просто отправьте HTTP GET
Приложение может иметь только одну подписку на каждый из возможных типов объектов. Если вы добавляете объект, на который уже есть подписка, то существующая подписка будет заменена на новую. Чтобы добавить или изменить подписку, вы должны отправить POST запрос, содержащий поля:
Получение списка из всех объектов а также их поля, на которые вы подписались
Сделав GET запрос на URL подписки
Чтобы удалить всю подписку на все объекты, отправьте DELETE запрос. Если вы хотите удалить подписку на конкретный объект, укажите параметр object (например, object=user).
Сервера Facebook делают HTTP GET запрос на ваш callback_url когда вы пытаетесь добавить или модифицировать подписку. После успешной подписки, сервера Facebook будут отправлять уведомления о изменениях, используя HTTP POST, на тот же URL.
До того как подписка будет окончательно добавлена или модифицирована, сервера Facebook сделают HTTP GET на ваш callback_url со следующими параметрами:
Скрипт обработки обновлений данных должен первым делом проверить значение hub.verify_token — “секретный код”, который вы передали в Facebook, а потом вернуть обратно параметр hub.challenge. Это сделано специально, чтобы оградить скрипт как средство проведения DDoS атаки на сервер.
Примечание для разработчиков: В PHP, точка конвертируется автоматически в подчеркивание в параметрах. Поэтому вы должны обращаться к
Когда данные изменяются, и есть валидная подписка, сервера Facebook делают HTTP POST запрос на callback_url, который вы задавали. Тип контента запроса будет application/json; тело — JSON-encoded строка, содержащая информацию об одном или нескольких изменениях. Пример можно будет посмотреть ниже в коде приложения.
Стоит отметить, что в строке не будут содержаться данные об актуальном значении. Поэтому вы должны будете сделать обычный запрос к API чтобы их получить (из-за политики безопасности). Вы можете загрузить нужные данные немедленно, чтобы пользователь, вернувшись в приложении не испытывал осложнений с увеличением времени загрузки.
Facebook агрегирует изменения и отправляет их пакетами каждые 5 секунд, или если количество произошедших изменений превысило 1000. В случае, когда уведомление о изменении не было доставлено к вам, Facebook повторит попытку заново, а затем немного позже, уменьшая частоту запросов в следующие 24 часа.
Применим теорию на практике. Для этого будет нужен хостинг, скрипт PHP, который будет располагаться на вашем домене по заданному вами адресу callback_url. Также вам потребуется приложение в Facebook. Вы можете использовать существующее, или создать новое на странице приложений разработчика.
Сохраните скрипт для callback_url
После этого воспользуемся новым инструментом для разработчиков Facebook — Graph API Explorer.
Выберите POST запрос чтобы добавить подписку и заполните все поля. Чтобы получить access_token (приложения), откройте в браузере ссылку, заполнив app-id и app-secret данными вашего приложения.
Путь до скрипта может быть facebook/callback.php например. Важно, что app-secret вы берете из настроек приложения, а секретный код в verify_token вы придумываете сами!
Итак, если после нажатия Submit в сером поле внизу ничего не произошло, значит вы все-таки добавили подписку на связи friends объекта user, и теперь как только любой пользователь вашего приложения добавит или удалил кого-то из друзей — Facebook отправит на callback_url вам уведомление. Я своем примере я добавил подписку еще и на offline_access объекта permissions.
Если у вас ваше приложение было установлено — ничего страшного. Если нет — тоже. Последовательность действий одинаковая.
Сначала нужно добавить разрешение offline_access. Если приложение не было установлено — это произойдет автоматически. У меня приложение не установлено. Попробую вызвать окно авторизации через строку браузера. Откройте ссылку, заменив в ней app-id на id вашего приложения, и заменив site-url на http://<ваш домен>:
После удачной авторизации Facebook редиректит вас на http://<ваш домен>/?code=…
По логике, которая содержится в скрипте — при обработке входящего уведомления мы просто добавляем переданную JSON-encoded строку в текстовый файл data.txt, который будет находиться в одной директории со скриптом. Проверьте, создался ли этот файл и какую информацию он содержит.
У меня добавленная информация выглядит так:
Как видно — я и установил приложение, и разрешил offline_access permission. По uid вы можете определять пользователя у которого изменились данные, а по time — время добавления.
Вы можете зайти в настройки приложений на Facebook, открыть ваше приложение и удалить разрешение offline_access. В файле data.txt вы увидите, что вам опять прислали уведомление. Можете также добавить или удалить кого-то из друзей — вы увидите что и эти уведомления, на которые вы подписались, будут приходить на callback_url и обрабатываться вашим скриптом.
Теперь вы знаете о замечательной возможности Facebook Real-Time Updates, которая может присылать вам информацию о изменениях данных пользователя и разрешений. К сожалению, почему-то при удалении пользователем приложения данные не изменились. Поэтому как бы новый способ не экономил время и ресурсы — все-таки при реализации определенных задач (например, отправка почтовой рассылки всем пользователям приложения) еще стоит предварительно обходить через обычное API всех пользователей в вашей базе данных, проверяя, установлено ли у них ваше приложение.
Есть два способа для того, чтобы получать данные не только во время работы пользователя с приложением:
- Получить от пользователя offline_access permission (сохранить “вечный” пользовательский access_token) и получать необходимые данные “по расписанию” (дергать скрипт cron-ом).
- Написать скрипт, который будет получать все изменения данных от Facebook, настроить и подписаться на обновления через Real-Time Updates.
Под катом вы узнаете виртуальный пример, как использование real-time updates помогает сократить за день количество запросов к API более чем в 100 раз в некоторых ситуациях. Мы напишем скрипт подписки на обновления и проверим его работу, получив данные о изменении объектов от самого Facebook.
В начале статьи содержится много теории, которая похожа на русский перевод страницы документации с Facebook. Если вам проще читать на английском — вы можете пропустить все во Втором способе до раздела Пример работы Real-Time Updates. Но мне после первого прочтения настроить данный функционал почему-то не удалось. Надеюсь эта статья вам поможет быстрее разобраться в этом.
Первый способ
Функционал некоторых приложений может быть связан с необходимостью получать данные по расписанию. Например, вы собираете статистику количества лайков страниц из определенного каталога. Для этого вы получаете данные с периодичностью раз в час. Это правильный пример использования, по другому вы эти данные просто не получите. Но часто этот способ применяют и для объектов, по которым обновления можно получать не “по расписанию” а real-time от самого Facebook.
Из серьезных недостатков первого способа можно выделить следующие:
- Чем реже проверяются данные, тем меньше их достоверность.
- Высокие затраты ресурсов при частом обновлении.
- Пользователи с неохотой разрешают offline_access — доступ в любое время к их данным.
Представьте что вы сделали приложение, функционал которого завязан на друзьях пользователя, и вам очень важно иметь самую свежую информацию. Допустим ваше приложение установили 1000 пользователей. И пусть приемлемым временем кеширования данных о друзьях будет 1 час. В итоге каждый день вы будете отправлять 24000 запросов для того, чтобы ваша база данных о друзьях пользователя была актуальна! А у вас всего 1000 пользователей, и можно предположить, что изменений в друзьях на всех за день будет не больше пары сотен (ну это догадка, основанная на личном опыте).
Чтобы решить недостатки первого способа, Facebook сделал Real-Time Updates для своего Graph API.
Второй способ
Поддержка обновлений в реальном времени позволяет вашему приложению подписаться на изменения в данных в Facebook. Ваше приложение получает обновления от Facebook и сохраняет данные, вместо того, чтобы опрашивать серверы Facebook “по расписанию”. Кэширование данных и использование этого API могут улучшить надежность приложения и уменьшить его время загрузки. Всякий раз, когда происходит изменение на которое вы подписаны, Facebook делает HTTP POST запрос к скрипту обработки обновлений данных со списком изменений. Сервер пошлет вам уведомление об изменении в течение пары минут после его появления.
Объекты
На данный момент вы можете подписаться на следующие типы объектов:
- user (пользователь) — получать уведомления о конкретных полях и связях пользователя с соответствующими узлами Graph API.*
- permissions (разрешения) — получать уведомления когда пользователь изменяет разрешения для вашего приложения.
- page (страница) — получать уведомления когда страницы, которые добавили (установили) ваше приложение, изменяют их общие свойства.
* Не на все свойства и связи объекта User вы сможете подписаться. Например, вам доступны связи: feed, friends, activities, interests, music, books, movies, television, likes, checkins. Но при этом подписаться на изменения этих связей вы пока не сможете: home, tagged, posts, photos, albums, videos, groups, notes, events, inbox, outbox, updates, accounts
Подписка
Для того, чтобы настроить подписку на обновления, вам нужно:
- Настроить скрипт (URL) который будет получать как HTTP GET (для верификации подписки) так и POST (о изменении данных) запросы от Facebook.
- Сделать запрос POST к Graph API
https://graph.facebook.com/<app-id>/subscriptions
чтобы подписаться, и быть готовым к обработке запроса верификации.
Отправив запрос на
https://graph.facebook.com/<app-id>/subscriptions?access_token=...вы можете делать три вещи, смотря какой запрос HTTP POST, GET, or DELETE вы посылаете:
- Добавить и изменить подписку (POST).
- Получить список из всех объектов а также их поля, на которые вы подписались (GET)
- Удалить подписку (DELETE)
В запрос должен быть включен access_token приложения, который можно получить, используя ID вашего приложения (app-id) и секретный ключ приложения (app-secret). Просто отправьте HTTP GET
https://graph.facebook.com/oauth/access_token?client_id=<app-id>&client_secret=<app-secret>&grant_type=client_credentialsи в ответе придет: access_token=…
Добавление и изменение подписки
Итак, вы прочитали выше куда нужно отправлять запрос для добавления подписки. Не спешите сразу выполнять эти запросы — структура изложения материала не такая, как последовательность нужных шагов. Сделано это специально, чтобы изучать материал последовательно. А вот в примере вы будете первыми выполнять запросы, которые описаны в последней части перед примером.
Приложение может иметь только одну подписку на каждый из возможных типов объектов. Если вы добавляете объект, на который уже есть подписка, то существующая подписка будет заменена на новую. Чтобы добавить или изменить подписку, вы должны отправить POST запрос, содержащий поля:
- object — тип объекта: user, permissions или page. Вы будете мониторить все объекты этого типа, например, всех пользователей вашего приложения.
- fields — Список (элементы разделены запятыми) свойств и связей выбранного объекта. Например, чтобы следить за изменениями в полях name, picture, friends пользователя, а также связи News Feed, вы должны указать значение “name,picture,friends,feed”
- callback_url — URL на который Facebook будет отправлять изменения, на которые подписано приложение.
- verify_token — “секретный код”, который вы задаете для того, чтобы проверить подлинность запроса. Он будет передан в скрипт, обрабатывающий подписку.
Получение списка из всех объектов а также их поля, на которые вы подписались
Сделав GET запрос на URL подписки
https://graph.facebook.com/<app-id>/subscriptions?access_token=...вы получите ответ с JSON-encoded контентом, который перечисляет ваши подписки. Я подписался на связь friends объекта user, а также на offline_access в permissions. Вот как выглядит ответ:
{ "data": [ { "object": "user", "callback_url": "http://millione.tv/<путь до скрипта>", "fields": [ "friends" ], "active": true }, { "object": "permissions", "callback_url": "http://millione.tv/<путь до скрипта>", "fields": [ "offline_access" ], "active": true } ] }
Удаление подписки
Чтобы удалить всю подписку на все объекты, отправьте DELETE запрос. Если вы хотите удалить подписку на конкретный объект, укажите параметр object (например, object=user).
Ваш Callback сервер
Сервера Facebook делают HTTP GET запрос на ваш callback_url когда вы пытаетесь добавить или модифицировать подписку. После успешной подписки, сервера Facebook будут отправлять уведомления о изменениях, используя HTTP POST, на тот же URL.
Верификация подписки
До того как подписка будет окончательно добавлена или модифицирована, сервера Facebook сделают HTTP GET на ваш callback_url со следующими параметрами:
- hub.mode — Строка ‘subscribe’ передается в этом параметре.
- hub.challenge — Случайная строка.
- hub.verify_token — “секретный код”, который вы задаете для того, чтобы проверить подлинность запроса, который вы передали Facebook.
Скрипт обработки обновлений данных должен первым делом проверить значение hub.verify_token — “секретный код”, который вы передали в Facebook, а потом вернуть обратно параметр hub.challenge. Это сделано специально, чтобы оградить скрипт как средство проведения DDoS атаки на сервер.
Примечание для разработчиков: В PHP, точка конвертируется автоматически в подчеркивание в параметрах. Поэтому вы должны обращаться к
$_GET["hub_mode"]
, $_GET["hub_challenge"]
и $_GET["hub_verify_token"]
.Уведомления об изменениях
Когда данные изменяются, и есть валидная подписка, сервера Facebook делают HTTP POST запрос на callback_url, который вы задавали. Тип контента запроса будет application/json; тело — JSON-encoded строка, содержащая информацию об одном или нескольких изменениях. Пример можно будет посмотреть ниже в коде приложения.
Стоит отметить, что в строке не будут содержаться данные об актуальном значении. Поэтому вы должны будете сделать обычный запрос к API чтобы их получить (из-за политики безопасности). Вы можете загрузить нужные данные немедленно, чтобы пользователь, вернувшись в приложении не испытывал осложнений с увеличением времени загрузки.
Facebook агрегирует изменения и отправляет их пакетами каждые 5 секунд, или если количество произошедших изменений превысило 1000. В случае, когда уведомление о изменении не было доставлено к вам, Facebook повторит попытку заново, а затем немного позже, уменьшая частоту запросов в следующие 24 часа.
Пример работы Real-Time Updates
Применим теорию на практике. Для этого будет нужен хостинг, скрипт PHP, который будет располагаться на вашем домене по заданному вами адресу callback_url. Также вам потребуется приложение в Facebook. Вы можете использовать существующее, или создать новое на странице приложений разработчика.
1. Приложение
2. Скрипт обработки обновлений данных
Сохраните скрипт для callback_url
<?php
/* Note the request must complete within 15 seconds.
Otherwise Facebook server will consider it a timeout and
resend the push notification again. */
define('VERIFY_TOKEN', '<secret_code>');
$method = $_SERVER['REQUEST_METHOD'];
if ($method == 'GET' && $_GET['hub_mode'] == 'subscribe'
&& $_GET['hub_verify_token'] == VERIFY_TOKEN) {
echo $_GET['hub_challenge'];
} else
if ($method == 'POST') {
$data = file_get_contents("php://input");
$fh = fopen('data.txt','a') or die('open file');
if (-1 == fwrite($fh, $data)) { die('write data'); }
fclose($fh) or die('close file');
}
?>
3. Добавляем подписку
После этого воспользуемся новым инструментом для разработчиков Facebook — Graph API Explorer.
Выберите POST запрос чтобы добавить подписку и заполните все поля. Чтобы получить access_token (приложения), откройте в браузере ссылку, заполнив app-id и app-secret данными вашего приложения.
https://graph.facebook.com/oauth/access_token?client_id=<app-id>&client_secret=<app-secret>&grant_type=client_credentials
Путь до скрипта может быть facebook/callback.php например. Важно, что app-secret вы берете из настроек приложения, а секретный код в verify_token вы придумываете сами!
Итак, если после нажатия Submit в сером поле внизу ничего не произошло, значит вы все-таки добавили подписку на связи friends объекта user, и теперь как только любой пользователь вашего приложения добавит или удалил кого-то из друзей — Facebook отправит на callback_url вам уведомление. Я своем примере я добавил подписку еще и на offline_access объекта permissions.
4. Создаем активность пользователя
Если у вас ваше приложение было установлено — ничего страшного. Если нет — тоже. Последовательность действий одинаковая.
Сначала нужно добавить разрешение offline_access. Если приложение не было установлено — это произойдет автоматически. У меня приложение не установлено. Попробую вызвать окно авторизации через строку браузера. Откройте ссылку, заменив в ней app-id на id вашего приложения, и заменив site-url на http://<ваш домен>:
https://www.facebook.com/dialog/oauth?client_id=<app-id>&redirect_uri=<site-url>&scope=offline_access
После удачной авторизации Facebook редиректит вас на http://<ваш домен>/?code=…
По логике, которая содержится в скрипте — при обработке входящего уведомления мы просто добавляем переданную JSON-encoded строку в текстовый файл data.txt, который будет находиться в одной директории со скриптом. Проверьте, создался ли этот файл и какую информацию он содержит.
У меня добавленная информация выглядит так:
{"object":"permissions","entry":[{"uid":"100001828786121","id":"100001828786121","time":1310669052,"changed_fields":["connected"]},{"uid":"100001828786121","id":"100001828786121","time":1310669052,"changed_fields":["offline_access"]}]}
Как видно — я и установил приложение, и разрешил offline_access permission. По uid вы можете определять пользователя у которого изменились данные, а по time — время добавления.
5. Действия при удалении
Вы можете зайти в настройки приложений на Facebook, открыть ваше приложение и удалить разрешение offline_access. В файле data.txt вы увидите, что вам опять прислали уведомление. Можете также добавить или удалить кого-то из друзей — вы увидите что и эти уведомления, на которые вы подписались, будут приходить на callback_url и обрабатываться вашим скриптом.
Выводы
Теперь вы знаете о замечательной возможности Facebook Real-Time Updates, которая может присылать вам информацию о изменениях данных пользователя и разрешений. К сожалению, почему-то при удалении пользователем приложения данные не изменились. Поэтому как бы новый способ не экономил время и ресурсы — все-таки при реализации определенных задач (например, отправка почтовой рассылки всем пользователям приложения) еще стоит предварительно обходить через обычное API всех пользователей в вашей базе данных, проверяя, установлено ли у них ваше приложение.