通过Http与twitter服务器通信:
如何构建 Scitter 客户机来处理经过验证和未经过验证的调用。目前,我将采用典型的 Scala 方式,假定验证是 “按对象” 执行的,因此将需要验证的调用放在类定义中,并在未验证的调用放在对象定义中,测试代码(apache common httpclient包):
package com.tedneward.scitter
{
/**
* Object for consuming "non-specific" Twitter feeds, such as the public timeline.
* Use this to do non-authenticated requests of Twitter feeds.
*/
object Scitter
{
import org.apache.commons.httpclient._, methods._, params._, cookie._
/**
* Ping the server to see if it's up and running.
*
* Twitter docs say:
* test
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
* URL: http://twitter.com/help/test.format
* Formats: xml, json
* Method(s): GET
*/
def test : Boolean =
{
val client = new HttpClient()
val method = new GetMethod("http://twitter.com/help/test.xml")
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false))
client.executeMethod(method)
val statusLine = method.getStatusLine()
statusLine.getStatusCode() == 200
}
}
/**
* Class for consuming "authenticated user" Twitter APIs. Each instance is
* thus "tied" to a particular authenticated user on Twitter, and will
* behave accordingly (according to the Twitter API documentation).
*/
class Scitter(username : String, password : String)
{
}
}
实现用户验证的api实现:
package com.tedneward.scitter
{
import org.apache.commons.httpclient._, auth._, methods._, params._
// ...
/**
* Class for consuming "authenticated user" Twitter APIs. Each instance is
* thus "tied" to a particular authenticated user on Twitter, and will
* behave accordingly (according to the Twitter API documentation).
*/
class Scitter(username : String, password : String)
{
/**
* Verify the user credentials against Twitter.
*
* Twitter docs say:
* verify_credentials
* Returns an HTTP 200 OK response code and a representation of the
* requesting user if authentication was successful; returns a 401 status
* code and an error message if not. Use this method to test if supplied
* user credentials are valid.
* URL: http://twitter.com/account/verify_credentials.format
* Formats: xml, json
* Method(s): GET
*/
def verifyCredentials : Boolean =
{
val client = new HttpClient()
val method = new GetMethod("http://twitter.com/help/test.xml")
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false))
client.getParams().setAuthenticationPreemptive(true)
val creds = new UsernamePasswordCredentials(username, password)
client.getState().setCredentials(
new AuthScope("twitter.com", 80, AuthScope.ANY_REALM), creds)
client.executeMethod(method)
val statusLine = method.getStatusLine()
statusLine.getStatusCode() == 200
}
}
}
现在可以添加的最简单的 API 是 public_timeline,它收集 Twitter 从所有用户处接收到的最新的
n
更新,并返回它们以便于进行使用。与之前讨论的另外两个 API 不同,public_timeline API 返回一个响应主体(而不是仅依赖于状态码),因此我们需要分解生成的 XML/RSS/ATOM/,然后将它们返回给 Scitter 客户机。
package com.tedneward.scitter.test
{
class ExplorationTests
{
// ...
@Test def callTwitterPublicTimeline =
{
val publicFeedURL = "http://twitter.com/statuses/public_timeline.xml"
// HttpClient API 101
val client = new HttpClient()
val method = new GetMethod(publicFeedURL)
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false))
client.executeMethod(method)
val statusLine = method.getStatusLine()
assertEquals(statusLine.getStatusCode(), 200)
assertEquals(statusLine.getReasonPhrase(), "OK")
val responseBody = method.getResponseBodyAsString()
System.out.println("callTwitterPublicTimeline got... ")
System.out.println(responseBody)
}
}
}
这样就获得了返回的主体,接下来,我们要实现通过客户端完成twitter的更新
package com.tedneward.scitter
{
class Scitter
{
// ...
def update(message : String, options : OptionalParam*) : Option[Status] =
{
def optionsToMap(options : List[OptionalParam]) : Map[String, String]=
{
options match
{
case hd :: tl =>
hd match {
case InReplyToStatusId(id) =>
Map("in_reply_to_status_id" -> id.toString) ++ optionsToMap(tl)
case _ =>
optionsToMap(tl)
}
case List() => Map()
}
}
val paramsMap = Map("status" -> message) ++ optionsToMap(options.toList)
val (statusCode, body) =
Scitter.execute("http://twitter.com/statuses/update.xml",
paramsMap, username, password)
if (statusCode == 200)
{
Some(Status.fromXml(XML.loadString(body)))
}
else
{
None
}
}
}
}