Статьи

Facebook и Twitter: за кулисами


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

И хорошая новость заключается в том, что в SaaS-сервисах нет ничего волшебного, это просто набор веб-серверов, которые отвечают на конкретные запросы HTTP / HTTPS с помощью JSON или XML вместо HTML, а формат этих запросов публикуется поставщиками SaaS на их веб-сайты.

Например, Twitter публикует то, что он называет своими REST API RESOURCES, которые вы можете найти по этому адресу:

https://dev.twitter.com/docs/api

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

  private List<Tweet> queryForTweets(String screenName) {

    TimelineOperations timelineOps = twitter.timelineOperations();
    List<Tweet> results = timelineOps.getUserTimeline(screenName);
    logger.info("Fond Twitter timeline for :" + screenName + " adding " + results.size()
        + " tweets to model");
    return results;
  }

… который, я подозреваю, не глядя на код,

отправляет

запрос :
https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=roghughe
… и затем читает ответ, который будет выглядеть примерно так:

[{"created_at":"Fri Jun 15 19:58:49 +0000 2012","id":213722250153697280,"id_str":"213722250153697280","text":"RT @joshbloch: Incredibly depressing (to me) article on the state and future of Apple hardware http:\/\/t.co\/Mwv7MZFz . If I can't hack it ...","source":"\u003ca href=\"http:\/\/www.echofon.com\/\" rel=\"nofollow\"\u003eEchofon\u003c\/a\u003e","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":117413536,"id_str":"117413536","name":"Roger Hughes","screen_name":"roghughe","location":"UK","description":"","url":"http:\/\/www.captaindebug.com","protected":false,"followers_count":11,"friends_count":18,"listed_count":0,"created_at":"Thu Feb 25 13:51:47 +0000 2010","favourites_count":87,"utc_offset":0,"time_zone":"London","geo_enabled":false,"verified":false,"statuses_count":19,"lang":"en","contributors_enabled":false,"is_translator":false,"profile_background_color":"B2DFDA","profile_background_image_url":"http:\/\/a0.twimg.com\/images\/themes\/theme13\/bg.gif","profile_background_image_url_https":"https:\/\/si0.twimg.com\/images\/themes\/theme13\/bg.gif","profile_background_tile":false,"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/729683837\/Head1_normal.jpg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/729683837\/Head1_normal.jpg","profile_link_color":"93A644","profile_sidebar_border_color":"EEEEEE","profile_sidebar_fill_color":"FFFFFF","profile_text_color":"333333","profile_use_background_image":true,"show_all_inline_media":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null},"geo":null,"coordinates":null,"place":null,"contributors":null,"retweeted_status":{"created_at":"Fri Jun 15 19:19:51 +0000 2012","id":213712443388600320,"id_str":"213712443388600320","text":"Incredibly depressing (to me) article on the state and future of Apple hardware http:\/\/t.co\/Mwv7MZFz . If I can't hack it, I don't want it.","source":"web","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":61135090,"id_str":"61135090","name":"Joshua Bloch","screen_name":"joshbloch","location":"Silicon Valley","description":"Effective Java author, API Designer, Swell guy","url":null,"protected":false,"followers_count":15836,"friends_count":94,"listed_count":942,"created_at":"Wed Jul 29 06:50:55 +0000 2009","favourites_count":3,"utc_offset":-28800,"time_zone":"Pacific Time (US & Canada)","geo_enabled":false,"verified":false,"statuses_count":1017,"lang":"en","contributors_enabled":false,"is_translator":false,"profile_background_color":"BADFCD","profile_background_image_url":"http:\/\/a0.twimg.com\/images\/themes\/theme12\/bg.gif","profile_background_image_url_https":"https:\/\/si0.twimg.com\/images\/themes\/theme12\/bg.gif","profile_background_tile":false,"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/1778383824\/joshbloch.original-1326394501_normal.jpg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/1778383824\/joshbloch.original-1326394501_normal.jpg","profile_link_color":"FF0000","profile_sidebar_border_color":"F2E195","profile_sidebar_fill_color":"FFF7CC","profile_text_color":"0C3E53","profile_use_background_image":true,"show_all_inline_media":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null},"geo":null,"coordinates":null,"place":null,"contributors":null,"retweet_count":66,"entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/Mwv7MZFz","expanded_url":"http:\/\/goo.gl\/jmkfM","display_url":"goo.gl\/jmkfM","indices":[80,100]}],"user_mentions":[]},"favorited":false,"retweeted":false,"possibly_sensitive":false},"retweet_count":66,"entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/Mwv7MZFz","expanded_url":"http:\/\/goo.gl\/jmkfM","display_url":"goo.gl\/jmkfM","indices":[95,115]}],"user_mentions":[{"screen_name":"joshbloch","name":"Joshua Bloch","id":61135090,"id_str":"61135090","indices":[3,13]}]},"favorited":false,"retweeted":false,"possibly_sensitive":false},{"created_at":"Fri Jun 15 17:54:37 +0000 2012","id":213690991708880897,"id_str":"213690991708880897","text":"RT @bobbyllew: RT @jeffjarvis: In solidarity, every schoolkid everywhere should start tweeting pix of their meals:  http:\/\/t.co\/NWeROWBo","source":"\u003ca href=\"http:\/\/www.echofon.com\/\" rel=\"nofollow\"\u003eEchofon\u003c\/a\u003e","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":117413536,"id_str":"117413536","name":"Roger Hughes","screen_name":"roghughe","location":"UK","description":"","url":"http:\/\/www.captaindebug.com","protected":false,"followers_count":11,"friends_count":18,"listed_count":0,"created_at":"Thu Feb 25 13:51:47 +0000 2010","favourites_count":87,"utc_offset":0,"time_zone":"London","geo_enabled":false,"verified":false,"statuses_count":19,"lang":"en","contributors_enabled":false,"is_translator":false,"profile_background_color":"B2DFDA","profile_background_image_url":"http:\/\/a0.twimg.com\/images\/themes\/theme13\/bg.gif","profile_background_image_url_https":"https:\/\/si0.twimg.com\/images\/themes\/theme13\/bg.gif","profile_background_tile":false,"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/729683837\/Head1_normal.jpg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/729683837\/Head1_normal.jpg","profile_link_color":"93A644","profile_sidebar_border_color":"EEEEEE","profile_sidebar_fill_color":"FFFFFF","profile_text_color":"333333","profile_use_background_image":true,"show_all_inline_media":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null},"geo":null,"coordinates":null,"place":null,"contributors":null,"retweeted_status":{"created_at":"Fri Jun 15 12:37:47 +0000 2012","id":213611259055181826,"id_str":"213611259055181826","text":"RT @jeffjarvis: In solidarity, every schoolkid everywhere should start tweeting pix of their meals:  http:\/\/t.co\/NWeROWBo","source":"\u003ca href=\"http:\/\/www.tweetdeck.com\" rel=\"nofollow\"\u003eTweetDeck\u003c\/a\u003e","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":1077971,"id_str":"1077971","name":"Robert Llewellyn","screen_name":"bobbyllew","location":"London","description":"Conflicted wet liberal, amateur nerd, every few years Kryten in Red Dwarf. Electric vehicle fan and Stone Cold Fox (apparently)","url":"http:\/\/www.llewtube.com","protected":false,"followers_count":85654,"friends_count":668,"listed_count":3418,"created_at":"Tue Mar 13 09:20:36 +0000 2007","favourites_count":20,"utc_offset":0,"time_zone":"London","geo_enabled":false,"verified":true,"statuses_count":37079,"lang":"en","contributors_enabled":false,"is_translator":false,"profile_background_color":"253132","profile_background_image_url":"http:\/\/a0.twimg.com\/profile_background_images\/366726010\/NFGsmall.jpg","profile_background_image_url_https":"https:\/\/si0.twimg.com\/profile_background_images\/366726010\/NFGsmall.jpg","profile_background_tile":true,"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/1183945291\/twitterpic2_normal.jpg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/1183945291\/twitterpic2_normal.jpg","profile_link_color":"4242DA","profile_sidebar_border_color":"87BC44","profile_sidebar_fill_color":"A3DF0D","profile_text_color":"000000","profile_use_background_image":true,"show_all_inline_media":true,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null},"geo":null,"coordinates":null,"place":null,"contributors":null,"retweet_count":27,"entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/NWeROWBo","expanded_url":"http:\/\/bit.ly\/LrgTtP","display_url":"bit.ly\/LrgTtP","indices":[101,121]}],"user_mentions":[{"screen_name":"jeffjarvis","name":"Jeff Jarvis","id":11435642,"id_str":"11435642","indices":[3,14]}]},"favorited":false,"retweeted":false,"possibly_sensitive":false},"retweet_count":27,"entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/NWeROWBo","expanded_url":"http:\/\/bit.ly\/LrgTtP","display_url":"bit.ly\/LrgTtP","indices":[116,136]}],"user_mentions":[{"screen_name":"bobbyllew","name":"Robert Llewellyn","id":1077971,"id_str":"1077971","indices":[3,13]},{"screen_name":"jeffjarvis","name":"Jeff Jarvis","id":11435642,"id_str":"11435642","indices":[18,29]}]},"favorited":false,"retweeted":false,"possibly_sensitive":false}]

… который я обрезал, чтобы сэкономить место. Как только модуль Twitter получит вышеуказанные данные, он будет анализировать их в список бобов Tweet с использованием
JSON-процессора Jackson Java и нескольких других классов. Этот список бобов Tweet — это то, что ваше приложение получает в качестве возвращаемого значения для своего вызова.

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

https://developers.facebook.com/docs/reference/api/

Если вы видели образец Spring Social QuickStart, вы знаете, что он демонстрирует, как получить список ваших друзей на Facebook, используя следующий код:

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public String home(Model model) {
    List<Reference> friends = facebook.friendOperations().getFriends();
    model.addAttribute("friends", friends);
    return "home";
  }

и, как и код Twitter, приведенный выше, я готов поспорить, что код Кейта Дональда отображается в запросе API Facebook, который выглядит примерно так:

https://graph.facebook.com/me/friends?access_token=AAAAAAITEghMWiBBlEC5OGXjotoIjzn7r3KinZAWIbbleoHX1rYFlMMr9cvUmAEYEtQ1ZCHPFSbop2gXQ1ibbleeIWAbrZChwfrcywlYGTWIBBLeAVbjNnWjIlE

… результат которого аналогичным образом анализируется и возвращается в ваше приложение в виде списка POJO.

Однако обратите внимание на токен доступа или, чтобы дать ему полное имя, токен доступа OAuth. Это известно только вашему приложению и Facebook и используется для предоставления вашему приложению доступа к личным данным вашего пользователя. В этом и заключается суть OAuth: ваше приложение получает токен доступа, чтобы оно могло получить доступ к Facebook, LinkedIn, Sina Weibo или другим частным данным SaaS вашего пользователя.

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