理解“runwithfriends” Facebook应用示例代码

1 投票
1 回答
920 浏览
提问于 2025-04-17 09:14

这是我第一次接触网页编程,所以希望我的问题不会显得太傻。我在这个问题上卡了很多天。

我正在尝试理解一段示例代码: https://github.com/facebook/runwithfriends

不过我对信息流是怎么工作的,以及如何修改这个示例(也就是代码是怎么运作的)理解得不是很好。

比如,在以下这段代码中:

class RecentRunsHandler(BaseHandler):
"""Show recent runs for the user and friends"""
def get(self):
    if self.user:
        friends = {}
        for friend in select_random(
                User.get_by_key_name(self.user.friends), 30):
            friends[friend.user_id] = friend

        self.render(u'runs',
            friends=friends,
            user_recent_runs=Run.find_by_user_ids(
                [self.user.user_id], limit=5),
            friends_runs=Run.find_by_user_ids(friends.keys()),
        )
    else:
        self.render(u'welcome')

我理解到(结合HTML)是用来展示正在使用同一个应用的朋友,如果我理解没错,这里是关键部分:

*friends_runs=Run.find_by_user_ids(friends.keys())*

但是如果我想展示某个特定的朋友,我该怎么做呢?

总结一下,我想知道:

1- 这段代码的流程是怎么运作的?(我对这里的解释不是很理解)

2- 我该如何修改代码,以便展示用户的朋友列表(不一定是使用同一个应用的朋友)?而且,我能否根据某些特征(比如性别)来筛选朋友?

非常感谢!

1 个回答

1

我使用的Facebook的“SDK”是从https://gist.github.com/1190267上获取的,并结合了示例应用的代码,以实现我想要的功能,既可以用于画布应用,也可以用于网站。

这取决于你是用Facebook做网站还是画布应用。如果是画布应用,你可能可以用JavaScript SDK,但对于“用Facebook登录”,我需要一些服务器端的逻辑,这样即使JavaScript关闭也能正常工作。所以我完成了这个解决方案,里面有一些你可能需要知道的细节。你可以尝试对那个特定的应用“runwithfriends”做一些小改动,以了解每段代码的作用。不过,你看到的项目里有些做法已经过时了:

  • 现在获取和设置cookies,最好使用webapp2自带的功能,而不是FB示例应用里的代码。

  • 现在的登录和登出是用OAuth 2.0来做的,所以你看到的登录系统可能已经过时了,你需要使用OAuth 2.0,具体可以在这里找到。我更喜欢在服务器端处理登录/登出,所以我做了一个纯Python的OAuth 2.0解决方案,按照FB的教程中的认证步骤来登录/登出。我需要清除cookie才能让用户登出,这一点没有文档说明。

  • 为了升级到Python 2.7,我还需要修改代码,以确保HTTP头不会被转换成unicode。我不知道为什么,但如果不这样做,它会抱怨说头部“不是字符串”。

为了更详细地回答你的具体问题:

1) 你发布的requesthandler类是BaseHandler的一个子类,所以要完全理解它的功能,你可以查看BaseHandler类,因为你发布的就是一个BaseHandler。BaseHandler使用Django模板来渲染,如果你想的话,可以把模板引擎换成推荐的jinja2。此外,代码访问了从BaseHandler继承的用户对象,并对其进行了一些操作,然后渲染到模板中。你可以尝试自己创建一个requesthandler,继承BaseHandler,做你想做的事情。

2) 我能够修改代码,虽然我不是专家,所以你也应该能做到。我想要一个简单的FB应用来显示随机图片,我可以修改代码,通过blob选择随机图片,并渲染到模板中,同时保留Facebook的基本功能。获取用户的函数是通过Graph API来实现的,我这样做:

def parse_signed_request(signed_request, secret):
    """
    Parse signed_request given by Facebook (usually via POST),
    decrypt with app secret.

    Arguments:
    signed_request -- Facebook's signed request given through POST
    secret -- Application's app_secret required to decrpyt signed_request
    """

    if '.' in signed_request:
        (esig, payload) = signed_request.split('.')
    else:
        return {}

    sig = urlsafe_b64decode(str(esig))
    data = _parse_json(urlsafe_b64decode(str(payload)))

    if not isinstance(data, dict):
        raise SignedRequestError('Pyload is not a json string!')
        return {}

    if data['algorithm'].upper() == 'HMAC-SHA256':
        if hmac.new(secret, payload, hashlib.sha256).digest() == sig:
            return data
    else:

        raise SignedRequestError('Not HMAC-SHA256 encrypted!')

    return {}


def get_user_from_cookie(cookies, app_id, app_secret):
    """Parses the cookie set by the official Facebook JavaScript SDK.

    cookies should be a dictionary-like object mapping cookie names to
    cookie values.

    If the user is logged in via Facebook, we return a dictionary with the
    keys "uid" and "access_token". The former is the user's Facebook ID,
    and the latter can be used to make authenticated requests to the Graph API.
    If the user is not logged in, we return None.

    Download the official Facebook JavaScript SDK at
    http://github.com/facebook/connect-js/. Read more about Facebook
    authentication at http://developers.facebook.com/docs/authentication/.
    """
    cookie = cookies.get('fbsr_' + app_id, '')
    if not cookie:
        return None
    response = parse_signed_request(cookie, app_secret)
    if not response:
        return None

    args = dict(code=response['code'], client_id=app_id,
                client_secret=app_secret, redirect_uri='')

    file = \
        urllib.urlopen('https://graph.facebook.com/oauth/access_token?'
                       + urllib.urlencode(args))
    try:
        token_response = file.read()
    finally:
        file.close()

    access_token = cgi.parse_qs(token_response)['access_token'][-1]
    logging.debug('returning cookie')
    return dict(uid=response['user_id'], access_token=access_token)

完整的API文档可以查看http://developers.facebook.com/docs/api,你还可以在http://github.com/facebook/connect-js/获取官方的Facebook JavaScript SDK。

我现在正在编写代码,将webapp2_extras.auth账户与Facebook同步,以便自定义账户和Facebook账户可以共存,我们在webapp2小组和分类中讨论这个解决方案。我现在的做法是将推荐的current_user添加到basehandler中,并将其用作Facebook身份,同时在“合并”我的FBUser类,这个类是为授权我网站和/或画布应用的Facebook用户定制的,目的是与webapp2_extras.auth.models.User同步,这个模型是可扩展的,所以可以添加它没有的属性,比如facebookid、firstname、lastname等。

@property
def current_user(self):
    if not hasattr(self, '_current_user'):
        self._current_user = None
        cookie = get_user_from_cookie(self.request.cookies,
                facebookconf.FACEBOOK_APP_ID,
                facebookconf.FACEBOOK_APP_SECRET)
        if cookie:

            # Store a local instance of the user data so we don't need
            # a round-trip to Facebook on every request
            user = FBUser.get_by_key_name(cookie['uid'])
            if not user:
                graph = GraphAPI(cookie['access_token'])
                profile = graph.get_object('me')
                user = FBUser(key_name=str(profile['id']),
                              id=str(profile['id']),
                              name=profile['name'],
                              profile_url=profile['link'],
                              access_token=cookie['access_token'])
                user.put()
            elif user.access_token != cookie['access_token']:
                user.access_token = cookie['access_token']
                user.put()
            self._current_user = user
    return self._current_user

你也可以通过会话对象解决认证问题,并围绕此构建你的认证系统。这就是我在使用自定义账户和Facebook账户时所做的,你可以查看我的代码库,里面有更多关于如何用Python 2.7将Facebook与Google App Engine集成的代码示例。

撰写回答