做的项目是SNS相关的,想从facebook上扒些用户数据下来,学习了下Facebook API和restfb项目(Representational State Transfer)。
Facebook官方文档:http://developers.facebook.com/
1. 使用JavaScript从Facebook获取用户数据。
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'your-app-id',
channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true,
version : 'v2.1'
});
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
JavaScript SDK需要一个fb-root
元素,并用FB.init
初始化SDK。注意把YOUR_APP_ID
替换为从Facebook获取的ID。
fb-root
不能用display:none
或visibility:hidden
来隐藏,否则在IE下可能工作不正常。fb-root
也最好不要放在一个position:absolute
或position:relative
的元素中(fb-root
最好是放在靠近body开始处)。
SDK是异步加载的(js.async = true
),而SDK的加载协议则是根据页面的加载协议而定,可以是HTTP或HTTPS(js.src = "//..."
)。
当SDK加载完毕后,就会调用window.fbAsyncInit
,而FB.init
必须在其他初始化代码之前被调用,源码如下:
if(window.fbAsyncInit&&!window.fbAsyncInit.hasRun){
window.fbAsyncInit.hasRun=true;
fbAsyncInit();
}
Channel File 的作用是跨域访问,
channel.html
的内容可以仅仅是一行代码:
<script src="//connect.facebook.net/en_US/all.js"></script>
对通道文件而言,尽可能长的让它缓存。可以设置
Expires
来实现。如果没有适当的缓存,跨域访问则会非常慢。用PHP来写
channel.html
则是:
<?php
$cache_expire = 60*60*24*365;
header("Pragma: public");
header("Cache-Control: max-age=".$cache_expire);
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$cache_expire) . ' GMT');
?>
<script src="//connect.facebook.net/en_US/all.js"></script>
channelUrl
是可选的,但建议填写,它可以解决3方面的问题:
channelUrl
,社交化插件可能无法显示。 channelUrl
,而页面又包含自播放的音视频流,用户则可能听到2个声音,缘故是页面在跨域访问时将自动加载一次页面。 channelUrl
可以防止服务器日志记录产生重复计数。/*
* facebook相关JS
*/
FACEBOOK_COMMON = {
scope : "user_website,friends_website,user_birthday,friends_birthday,user_hometown,friends_hometown,user_friends,public_profile,email,read_stream,user_photos,user_videos,publish_stream,user_education_history,friends_education_history,user_location,friends_location,user_work_history,friends_work_history",
/*
获取自己和自己的facebook好友函数,异步保存用户自己的FB信息和FB好友信息
参数
needUpdate : 是否需要更新自己在好友手中的备份
needConnect : 是否需要登录FB true or fasle
返回object内的参数
friendArr : facebook好友
me : 我的信息
response : 服务端返回的信息
*/
getFriends : function(callback, needUpdate, needConnect){
var uid;
var accessToken ;
var expiresIn;
// 需要强制登录(存当保前用户的FB信息)的情况,使用FB.login方法,如果当前用户没有登录FaceBook,会弹出一个小窗口让用户登录
if(needConnect){
FB.login(function(response){
if(response.authResponse){
uid = response.authResponse.userID; // 取得 FBID
accessToken = response.authResponse.accessToken; // 取得 accessToken
expiresIn = response.authResponse.expiresIn;
FB.api('/me?locale=ja_JP', function(user) { // 获取用户自己的FACEBOOK信息
if(user != null) {
user.head = "https://graph.facebook.com/" + uid + "/picture"; // 头像
var name = user.name;
var data = "OAuthUid="+uid+"&accessToken="+accessToken+"&expiresIn="+expiresIn+"&name="+name;
$.ajax({
type:"get",
url: "yourURL?"+data, // 需要替换成你的后台处理的URL(存当保前用户的FB信息)
data: data,
success:function(responseObj) {
user.msg = responseObj.response;
// 调用自身,获取FB好友信息
FACEBOOK_COMMON.getFriends(callback, needUpdate, false);
},
error:function(responseObj){
console.log(responseObj.response);
}
});
}
});
}
},{scope : FACEBOOK_COMMON.scope});
return;
}
// 不需要强制登录的情况,使用FB.getLoginStatus方法,如果当前用户没有登录FaceBook,不会执行任何操作
FB.getLoginStatus(function(response){
if(response.status == 'connected'){
FB.api('/me?locale=ja_JP', function(user) {
if(user == null || user == undefined){
console.log("user is null !");
return;
}
if(user.error){
console.log(user.error.message);
FACEBOOK_COMMON.getFriends(callback, needUpdate, true);
}
uid = user.id
user.head = "https://graph.facebook.com/" + uid + "/picture";
// 获取FB好友
FACEBOOK_COMMON.sendFriendRequest(callback, user, needUpdate);
});
} else{
FACEBOOK_COMMON.getFriends(callback, needUpdate, true);
}
});
},
/*
获取该用户的所有FB好友信息
*/
sendFriendRequest : function(callback, me, needUpdate){
FB.api({ method: 'friends.get' }, function(idArr) {
var friendArr = new Array();
var returnData = new Object();
if(idArr.length == 0){
returnData.response = "no friend!";
callback(returnData);
return;
}
for(var i=0;i<idArr.length;i++){
// 循环中,通过FBID来获取详细信息
FB.api("/" + idArr[i] + "?locale=ja_JP", function(g) {
g.head = "https://graph.facebook.com/" + g.id + "/picture";
friendArr.push(g);
if(friendArr.length == idArr.length){
returnData.friendArr = friendArr;
returnData.me = me;
var friendRequest = encodeURIComponent(JSON.stringify(friendArr)); // 特殊字符编码处理
var meRequest;
//是否需要更新
if(needUpdate){
meRequest = encodeURIComponent(JSON.stringify(me));
}else{
meRequest = '';
}
$.ajax({
type:"get",
url: "yourURL?"+data, // 需要替换成你的后台处理的URL(保存当前用户的FB好友信息)
data: "friends="+friendRequest+"&me="+meRequest,
success:function(responseObj) {
returnData.response = responseObj.response;
callback(returnData);
},
error:function(responseObj){
console.log(responseObj.response);
}
});
}
});
}
});
}
}
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
// ...
HttpClient httpClient = new HttpClient();
httpClient.getParams().setParameter("http.protocol.content-charset","UTF-8");
String url = "https://graph.facebook.com/me?";
GetMethod getMethod = new GetMethod(url);
NameValuePair[] accessData = { new NameValuePair("access_token",accessToken) };
getMethod.setQueryString(accessData);
try {
httpClient.executeMethod(getMethod);
byte[] responseBody = getMethod.getResponseBody();
String responseStr = new String(responseBody, "utf-8");
if(StringUtils.isEmpty(responseStr)) {
System.out.println(responseStr);
}
} catch (Exception e) {
e.printStackTrace();
}
// ...
<dependency>
<groupId>com.restfb</groupId>
<artifactId>restfb</artifactId>
<version>1.6.16</version>
</dependency>
package com.maitian.register.controllers.guide;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.lang.StringUtils;
import org.slf4j.bridge.SLF4JBridgeHandler;
import com.restfb.Connection;
import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.Parameter;
import com.restfb.exception.FacebookException;
import com.restfb.exception.FacebookGraphException;
import com.restfb.exception.FacebookJsonMappingException;
import com.restfb.exception.FacebookNetworkException;
import com.restfb.exception.FacebookOAuthException;
import com.restfb.exception.FacebookResponseStatusException;
import com.restfb.types.User;
public class RestFBTest {
public static void main(String[] args) {
SLF4JBridgeHandler.install();
// 通过OAUTH认证获取
String accessToken = "CAAFeNg4fUMkBAOZBGwG26AzRVXJHb0ZA7ZCZAg83ATGytCHKNwZCt2jXY4BvqouLZCqc3ziMNtPGCQXpSK0GJZC5rGdZBknQOcCPrF9BWQ1qUSmmqAd75z9iMlpOXz4XjjWg7Y885XJB7IsoTxLKtwkcSNfWSqdd7GAkTqgFSS0jD39lrF4PnBQBQZCrcTABX7ilk306KhWURVgUSC4v1zVhf";
try {
// 方式一:直接调用API
HttpClient httpClient = new HttpClient();
httpClient.getParams().setParameter("http.protocol.content-charset","UTF-8");
// 获取用户FB信息
String url = "https://graph.facebook.com/me?";
GetMethod getMethod = new GetMethod(url);
NameValuePair[] accessData = { new NameValuePair("access_token",accessToken), new NameValuePair("locale","zh_CN") };
getMethod.setQueryString(accessData);
httpClient.executeMethod(getMethod);
byte[] responseBody = getMethod.getResponseBody();
String responseStr = new String(responseBody, "utf-8");
if(StringUtils.isNotEmpty(responseStr)) {
System.out.println(responseStr);
}
System.out.println("=====================================");
// 获取用户FB好友信息(只能取到名字和ID)
url = "https://graph.facebook.com/me/friends?";
getMethod = new GetMethod(url);
getMethod.setQueryString(accessData);
httpClient.executeMethod(getMethod);
responseBody = getMethod.getResponseBody();
responseStr = new String(responseBody, "utf-8");
if(StringUtils.isNotEmpty(responseStr)) {
System.out.println(responseStr);
}
System.out.println("+++++++++++++++++++++++++++++++++++++");
// 方式二:使用restfb
FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
User user = facebookClient.fetchObject("me", User.class, Parameter.with("locale", "zh_CN"));
System.out.println(user.getEmail());
System.out.println(user);
System.out.println("=====================================");
// (只能取到名字和ID)
Connection<User> myFriends = facebookClient.fetchConnection("me/friends", User.class, Parameter.with("locale", "zh_CN"));
List<String> fbids = new ArrayList<String>();
for (User friend : myFriends.getData()) {
// 通过FBID去获取好友详细信息
user = facebookClient.fetchObject(friend.getId(), User.class);
System.out.println(user);
fbids.add(friend.getId());
}
// 一次返回所有好友信息,需要自己封装返回类型
//<T> T = facebookClient.fetchObjects(fbids, Class<T> objectType, Parameter.with("locale", "zh_CN"));
} catch (FacebookJsonMappingException e) {
// Looks like this API method didn't really return a list of users
e.printStackTrace();
} catch (FacebookNetworkException e) {
// An error occurred at the network level
int code = e.getHttpStatusCode();
System.out.println("API returned HTTP status code " + e.getHttpStatusCode());
} catch (FacebookOAuthException e) { // Authentication failed - bad access token?
e.printStackTrace();
} catch (FacebookGraphException e) { // The Graph API returned a specific error
e.printStackTrace();
System.out.println("Call failed. API says: " + e.getErrorMessage());
} catch (FacebookResponseStatusException e) {
// Old-style Facebook error response.
// The Graph API only throws these when FQL calls fail.
// You'll see this exception more if you use the Old REST API
// via LegacyFacebookClient.
if (e.getErrorCode() == 200) {
System.out.println("Permission denied!");
}
} catch (FacebookException e) {
// This is the catchall handler for any kind of Facebook exception
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// Make sure to tear down when you're done using the bridge
SLF4JBridgeHandler.uninstall();
}
}
}