2013-09-28 95 views
0

我在Erlang世界非常新,我正在尝试为Twitter Stream API编写一个客户端。我正在使用httpc:请求发出POST请求,并且我经常收到401错误,我显然在如何发送请求时做错了什么...我的看起来像这样:Twitter流API - Erlang客户端

fetch_data() -> 
    Method = post, 
    URL = "https://stream.twitter.com/1.1/statuses/filter.json", 
    Headers = "Authorization: OAuth oauth_consumer_key=\"XXX\", oauth_nonce=\"XXX\", oauth_signature=\"XXX%3D\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"XXX\", oauth_token=\"XXX-XXXXX\", oauth_version=\"1.0\"", 
    ContentType = "application/json", 
    Body = "{\"track\":\"keyword\"}", 
    HTTPOptions = [], 
    Options = [], 
    R = httpc:request(Method, {URL, Headers, ContentType, Body}, HTTPOptions, Options), 
    R. 

在这一点上,我相信签名没有问题,因为当试图使用curl访问API时,相同的签名工作得很好。我猜我的提问方式存在一些问题。

我与请求得到响应作出上述证明的方式是:

{ok,{{"HTTP/1.1",401,"Unauthorized"}, 
[{"cache-control","must-revalidate,no-cache,no-store"}, 
    {"connection","close"}, 
    {"www-authenticate","Basic realm=\"Firehose\""}, 
    {"content-length","1243"}, 
    {"content-type","text/html"}], 
"<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n<title>Error 401 Unauthorized</title>\n</head>\n<body>\n<h2>HTTP ERROR: 401</h2>\n<p>Problem accessing '/1.1/statuses/filter.json'. Reason:\n<pre> Unauthorized</pre>\n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n            \n</body>\n</html>\n"}} 

当卷曲尝试我使用这个:

curl --request 'POST' 'https://stream.twitter.com/1.1/statuses/filter.json' --data 'track=keyword' --header 'Authorization: OAuth oauth_consumer_key="XXX", oauth_nonce="XXX", oauth_signature="XXX%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="XXX", oauth_token="XXX-XXXX", oauth_version="1.0"' --verbose 

和我得到的事件很好。

任何对此的帮助将不胜感激,与Erlang新和我一直拉我的头发在这一个相当长的一段时间。

+0

我使用OAuth:获得/ 6(https://github.com/tim/erlang-oauth)以'状态/ sample'连接到他们的信息流,你可以使用'的OAuth:对于POST'过滤流。 – akonsu

回答

5

有几个问题与您的代码

  1. 在二郎你的编码参数作为JSON的身体,而与curl,你是编码它们的表格数据(application/x-www-form-urlencoded)。 Twitter API预计后者。实际上,您得到401是因为OAuth签名不匹配,因为您在计算中包含track=keyword参数,而Twitter的服务器在没有JSON正文的情况下计算它,因为它应该按照OAuth RFC

  2. 您正在使用httpc默认选项。这不适用于流媒体API,因为流永远不会结束。您需要在到达时处理结果。为此,您需要将{sync, false}选项传递给httpc。另请参阅streamreceiver选项。

最后,而httpc可以开始工作访问Twitter流API,它带来的价值不大,你需要围绕它开发从Twitter的API来流的码。根据您的需要,您可能希望将其替换为一个直接基于ssl构建的简单客户端,特别是考虑到它可以解码HTTP数据包(HTTP留给您的是HTTP块编码)。

例如,如果您的关键字很少,您可能会从httpc获得暂停。此外,在没有httpc的情况下更新关键字列表或代码而不停机可能更容易。

直接基于ssl流媒体客户端可以实现为gen_server(或一个简单的过程,如果你不按照OTP原则),甚至更好gen_fsm实施重联的策略。你可以进行如下操作:

  • 连接使用所需的插座与{packet, http_bin}的HTTP报文进行解码ssl:connect/3,4指定和您想要的插座在被动模式{active, false}进行配置。

  • ssl:send/2,3发送HTTP请求包(优选地作为iolist,与二进制文件)。它应分散在多行用CRLF(\r\n)分隔的行上,首先查询行(GET /1.1/statuses/filter.json?... HTTP/1.1),然后是包含OAuth标题的标题。确保你也包含Host: stream.twitter.com。以空行结束。

  • 接收HTTP响应。你可以通过一个循环来实现它(因为套接字处于被动模式),调用ssl:recv/2,3,直到得到http_eoh(头部结尾)。请注意,服务器是否会通过查看Transfer-Encoding响应标题将数据分块发送给您。

  • 配置在主动模式下的插座与ssl:setopts/2并指定要在二进制格式的数据包作为原始和数据。事实上,如果数据被分块,您可以继续在被动模式下使用套接字。您也可以逐行获取数据或将数据作为字符串获取。这是一个有趣的问题:raw是最安全的赌注,逐行要求您检查缓冲区大小以防止截断长JSON编码的tweet。

  • 从Twitter接收数据发送到您的处理消息,无论是与receive(工艺简单),或在handle_info处理器(如果你实现了这个用gen_server)。如果数据被分块,您应该首先收到块大小,然后是tweets和块的末尾(参见RFC 2616)。准备好在几个区块上传播推文(即保留某种缓冲区)。这里最好的解决方法是在此过程中进行最低限度的解码,并将推文发送到另一个进程,可能采用二进制格式。

您还应该处理由Twitter关闭的错误和套接字。确保你按照Twitter's guidelines for reconnection

+0

我已经成功地使用'二郎 - oauth'库连接到Twitter的数据流和'二郎,oauth'似乎用'httpc':https://github.com/tim/erlang-oauth/blob/118e9f7284c81cb72e131e20bcecf5872a5cbe97/src /oauth.erl#L192。你能解释一下为什么你说'httpc'不起作用? – akonsu

+0

你是对的,httpc将以异步模式工作。我相应地更新了答案。 –

+0

@PaulGuyot感谢您的帮助。我现在已经成功地打开了一个socket到stream.twitter.com,似乎这部分工作得很好。然而,我有正确的方式通过套接字发送请求的问题。我试着用'ssl:send(SSLSocket,“POST /1.1/statuses/filter.json?oauth_consumer_key=XXX ...',用'ssl:send(SSLSocket,”POST%2F1.1%2Fstatuses%2Ffilter.json %26oauth_consumer_key%3DXXX'和其他格式,但它似乎我不能得到它的权利。如何预计通过套接字发送标头?感谢您的帮助! – Thanos