60行代码实现分享到微博,QQ空间,豆瓣 - 介绍好用的Faraday_Ruby_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > Ruby > 60行代码实现分享到微博,QQ空间,豆瓣 - 介绍好用的Faraday

60行代码实现分享到微博,QQ空间,豆瓣 - 介绍好用的Faraday

 2013/7/10 4:35:26  QuakeWang  程序员俱乐部  我要评论(0)
  • 摘要:因为项目需要在后台实现自动将内容同时分享到微博,QQ空间,豆瓣等各个社交网络,一开始准备找个现成的gem,发现了hooopo写的:https://github.com/hooopo/oauth_china但是这个项目微博用的是OAuth1,新浪很快就不支持了,原准备fork一下修改,但觉得依赖太多,而且我们的项目本身用了Omniauth做登录,用户的token等信息都已经拿到,其实只要用一个http客户端,将auth的信息放在header里面调用相对的api就行了。于是想起了以前用过的gem
  • 标签:实现 代码 微博 RAD QQ
因为项目需要在后台实现自动将内容同时分享到微博,QQ空间,豆瓣等各个社交网络,一开始准备找个现成的gem,发现了hooopo写的:
https://github.com/hooopo/oauth_china 但是这个项目微博用的是OAuth 1,新浪很快就不支持了,原准备fork一下修改,但觉得依赖太多,而且我们的项目本身用了Omniauth做登录,用户的token等信息都已经拿到,其实只要用一个http客户端,将auth的信息放在header里面调用相对的api就行了。于是想起了以前用过的gem: Faraday

先介绍一下Faraday, 它是一个ruby的http客户端,用类似rack middleware的方式来定制各种http调用。它本身并不实现http客户端,而是用adapter的方式对Net::HTTP, patron甚至 em-http 等提供了封装。非常简单易用,并且容易定制,当然再漂亮的介绍文字都比不过代码,还是上代码,看看它的用途吧。

首先是最基本发布文本到新浪微博,因为weibo接受将token作为一个参数传递,所以就2行代码搞定:
class="ruby">
  def weibo_update(text)
    conn = Faraday.new(:url => 'https://api.weibo.com')
    conn.post '/2/statuses/update.json', :access_token => self.token, :status => text
  end


然后是发布文本,同时上传一张图片到新浪微博,这个时候需要用到它的Middleware,在定义http connection中设置http request类型为multipart,同时使用Net::HTTP作为adapter(因为默认client的不支持multipart),然后文件使用Faraday::UploadIO,5行代码搞定:
  def weibo_upload(text, image_path)
    conn = Faraday.new(:url => 'https://api.weibo.com') do |f|
      f.request :multipart
      f.adapter :net_http
    end
    conn.post '/2/statuses/upload.json', :access_token => self.token, :status => text, :pic => Faraday::UploadIO.new(image_path, 'image/jpeg')
  end


同样的,分享到QQ空间,腾讯微博都只要用类似的方法处理,代码行数也都是2~5行(见文章最后)。
我们再来看看比较复杂的豆瓣 api,豆瓣用的Oauth 1只支持在header里面传递token,并且提交的内容不是key/value那样的form形式,而是xml,代码写成这样:
  def douban_saying(content)
    conn = Faraday.new(:url => 'http://api.douban.com') do |f|
      f.request :oauth, :consumer_key => self.app_id, :consumer_secret => self.app_key, :token => self.token, :token_secret => self.secret
      f.request :url_encoded
      f.adapter :net_http
    end
    conn.post do |req|
      req.url '/miniblog/saying'
      req.headers['Content-Type'] = 'application/atom+xml'
      req.body = <<-XML
        <?xml version='1.0' encoding='UTF-8'?>
          <entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
          <content>#{content}</content>
        </entry>
      XML
    end
  end

在request里面我们使用了oauth的middleware(由gem faraday_middleware提供),在header中插入oauth,同时在请求的时候,指定Content-Type,并将body内容设置成xml。但是在使用的时候发现一个问题,豆瓣必须要求header中的Authorization有OAuth realm=xxx的内容,于是我们得自己写一个middleware了,Faraday的middleware和rack很类似,只要实现一个call方法,在这里,我们用正则替换,在已经生成好的Authorization header中替换插入一段realm即可:
class DoubanOauthRealmMiddleware
  def initialize(app, options = {})
    @app = app
    @options = options
  end

  def call(env)
    env[:request_headers]["Authorization"] = env[:request_headers]["Authorization"].gsub(/^OAuth/, "OAuth realm=\"http://api.douban.com\",")
    @app.call(env)
  end  
end


然后将我们写的这个middleware,加入到上面的代码中,就搞定了:
	f.request :url_encoded      
	f.use DoubanOauthRealmMiddleware
	f.adapter :net_http


简单的介绍就结束了,其实Faraday还有更多非常棒的功能,比如对于response的自动json解析,自动retry,timeout处理等,都可以通过非常简洁的方式配置和middleware来实现,可以阅读它的源码来了解更多。

附录:发布到QQ空间,腾讯微博的代码,供有用的同学参考:
  def qq_add_share(summary, images, title, url)
    conn = Faraday.new(:url => 'https://graph.qq.com')
    conn.post '/share/add_share', :title => title, :url => url, :summary => summary, :images => images, :source => 1, :type => 4, :nswb => 1, 
      :access_token => self.token, :openid => self.provider_uid, :oauth_consumer_key => self.app_id
  end

  def qq_add_t(content)
    conn = Faraday.new(:url => 'https://graph.qq.com')
    conn.post '/t/add_t', :content => content, :syncflag => 1, :access_token => self.token, :openid => self.provider_uid, :oauth_consumer_key => self.app_id
  end

  def qq_add_pic_t(content, image_path)
    conn = Faraday.new(:url => 'https://graph.qq.com') do |f|
      f.request :multipart
      f.adapter :net_http
    end    
    conn.post '/t/add_pic_t', :content => content, :pic => Faraday::UploadIO.new(image_path, 'image/jpeg'), :syncflag => 1, :access_token => self.token, :openid => self.provider_uid, :oauth_consumer_key => self.app_id
  end
发表评论
用户名: 匿名