Twitter API 1.1使用c#搜索(在PCL中)

本文关键字:PCL 搜索 API 使用 Twitter | 更新日期: 2023-09-27 18:18:28

我有一个Windows 8和一个Windows Phone 8应用程序,作为一个社交媒体仪表板,它使用twitter搜索api获取tweet。这最初是使用Twitter API 1实现的,并且不需要身份验证,因此由于它不需要任何额外的第三方库,因此它被放置在解决方案的PCL部分。出于同样的原因,我希望在没有任何库的情况下更新到使用1.1 API。我在Twitter开发社区和codeproject上找到了各种在线示例,并将它们修改为与PCL一起工作。

下面是尝试搜索twitter的部分代码:

private static async Task<string> doTheTwitterMagic(string query)
    {
        var oauth_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_token_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_consumer_key = "XXXXXXXXXXXXXXXXX";
        var oauth_consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var resource_url = "https://api.twitter.com/1.1/search/tweets.json";
        // oauth implementation details
        var oauth_version = "1.0";
        var oauth_signature_method = "HMAC-SHA1";
        Encoding ascii = new AsciiEncoding();
        // unique request details
        var oauth_nonce = Convert.ToBase64String(
            ascii.GetBytes(DateTime.Now.Ticks.ToString()));
        var timeSpan = DateTime.UtcNow
            - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();

        // create oauth signature
        var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" +
                        "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&q={6}";
        var baseString = string.Format(baseFormat,
                                    oauth_consumer_key,
                                    oauth_nonce,
                                    oauth_signature_method,
                                    oauth_timestamp,
                                    oauth_token,
                                    oauth_version,
                                    Uri.EscapeDataString(query)
                                    );
        baseString = string.Concat("GET&", Uri.EscapeDataString(resource_url), "&", Uri.EscapeDataString(baseString));
        var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
                                "&", Uri.EscapeDataString(oauth_token_secret));
        string oauth_signature;
        using (HMACSHA1 hasher = new HMACSHA1(ascii.GetBytes(compositeKey)))
        {
            oauth_signature = Convert.ToBase64String(
                hasher.ComputeHash(ascii.GetBytes(baseString)));
        }
        // create the request header
        var headerFormat = "OAuth oauth_nonce='"{0}'", oauth_signature_method='"{1}'", " +
                           "oauth_timestamp='"{2}'", oauth_consumer_key='"{3}'", " +
                           "oauth_token='"{4}'", oauth_signature='"{5}'", " +
                           "oauth_version='"{6}'"";
        var authHeader = string.Format(headerFormat,
                                Uri.EscapeDataString(oauth_nonce),
                                Uri.EscapeDataString(oauth_signature_method),
                                Uri.EscapeDataString(oauth_timestamp),
                                Uri.EscapeDataString(oauth_consumer_key),
                                Uri.EscapeDataString(oauth_token),
                                Uri.EscapeDataString(oauth_signature),
                                Uri.EscapeDataString(oauth_version)
                        );
        return authHeader;
    }
public static async Task<List<TwitterObject>> GetTweetsFromSearchAsync(string query)
    {
        try
        {
            string authHeader = await doTheTwitterMagic(query);
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://api.twitter.com/1.1/search/tweets.json?q="+query);
            webRequest.Headers[HttpRequestHeader.Authorization] = authHeader;
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "GET";
            var webResponse = await webRequest.GetResponseAsync();
            var json = string.Empty;
            using (var reader = new StreamReader(webResponse.GetResponseStream()))
                json = await reader.ReadToEndAsync();
            var jsonObject = JObject.Parse(json);
            var results = new List<TwitterObject>();
            foreach (JToken token in jsonObject["results"])
                results.Add(token.ToObject<TwitterObject>());
            return results;
        }
        catch (Exception e) { throw e; }
    }

注意:: AsciiEncoding是AsciiEncoding的自定义实现,因为它目前在PCL中不可用。

现在我尝试了标准调试,我看的第一件事是Twitter OAuth工具,这里是OAuth工具与我的应用程序的结果

OAuth Tool Signature base string:

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&oauth_consumer_key
%3DywWuYGASkHMsHsC22Vpw%26oauth_nonce%3D3c30afb0c2a391d3b4e4ba3da057c2ca%26oauth_
signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1371309728%26oauth_token%3D16702
294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM%26oauth_version%3D1.0%26q%3Dcsmcr

我的应用签名基础字符串:

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&oauth_consumer_key
%3DywWuYGASkHMsHsC22Vpw%26oauth_nonce%3DNjM1MDY5MTA1MzA2MTU1NTgz%26oauth_signatur
e_method%3DHMAC-SHA1%26oauth_timestamp%3D1371310131%26oauth_token%3D16702294-3WNj
fZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM%26oauth_version%3D1.0%26q%3D%2540csmcr

乍一看,唯一的区别是nonce,但这应该不是问题编辑说明:我刚刚注意到,在OAuth工具中,我有%26q%3Dcsmcr,我的应用程序生成%26q%3D%2540csmcr,但这只是因为我忘记在OAuth工具的查询中包含一个字符。在添加字符后,字符串在末尾变得相同。

OAuth Tool Authorization header:

Authorization: OAuth oauth_consumer_key="ywWuYGASkHMsHsC22Vpw",    
oauth_nonce="3c30afb0c2a391d3b4e4ba3da057c2ca", 
oauth_signature="tofmGp6qaAUAPZnQHhQlVFWN40M%3D", 
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1371309728", 
oauth_token="16702294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM", 
oauth_version="1.0"

My app Authorization header:

Authorization: OAuth oauth_nonce="NjM1MDY5MDk5NTY5Nzc1MTc5", 
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1371309557", 
oauth_consumer_key="ywWuYGASkHMsHsC22Vpw", 
oauth_token="16702294-3WNjfZ9p0QWhEDPL1jR14s5safYhiruowHa3cXWbM", 
oauth_signature="q1544JDPUXdUwY3fmEk3mtGGEwk%3D", oauth_version="1.0"

除了nonce和签名没有太大区别。键值对的顺序似乎没有什么不同,因为我重新排列它们进行测试,仍然有同样的问题。

所以我遇到的问题是,当函数运行时,我总是得到401未经授权的错误与

{"errors":[{"message":"Could not authenticate you","code":32}]}

错误。

如能指点,不胜感激。

Edit:对此进行了更多的测试,采用了nonce和Twitter OAuth工具生成的时间戳,并在我的应用程序中对它们进行了硬编码,以检查签名是否正常,事实证明是这样,我得到了与OAuth工具相同的oauth_signature。这意味着Auth报头也应该完全没问题。所以我想问题是在我的请求。

Twitter API 1.1使用c#搜索(在PCL中)

(OP在问题编辑中回答)转换成社区维基的答案。参见没有答案的问题,但问题已在评论中解决(或在聊天中扩展))

OP写:

httpclient代替httpwebrequest实现解决了问题。问题是,Expect:100-Continue头被添加,和推特不支持这一点。由于PCL的限制,不可能在httpwebrequest中禁用此功能,将其全部替换为httpclie nt是一种方法。希望这篇文章能帮助到任何遇到同样问题的人。