2014-01-24 33 views
0

作为项目需求的一部分,OAuth从头开始实施,没有任何预先创建的库。 OAuth部分看起来工作正常(我们已经根据twitter的OAuth工具检查了许多签名结果),但是请求定期失败并带有401 error我在调试我们的Twitter的REST API v1.1实施时遇到了问题

由于OAuth至少看起来正在返回一个有效的Authorization头,我唯一能想到的可能是造成问题的原因是实际编码和发送头后生成的消息。

这是我们发出请求:

private string Tweet(string tweetTxt) 
{ 
    const string method = "POST"; 
    const string target = "https://api.twitter.com/1.1/statuses/update.json"; 

    NameValueCollection data = new NameValueCollection { { "status", tweetTxt } }; 
    NameValueCollection head = new NameValueCollection 
          { 
           {"user-agent", "AgentX"}, 
           {"Authorization", oauth.GetHttpHeader(method, target, null, data)} 
          }; 
    // example OAuth header return value (wrapped for readability): 
    // OAuth oauth_consumer_key="E6wtzO5DRloPq8Ba17osQ", 
    //  oauth_nonce="bfdc54f8b264e4d3d2595266b46d6118", 
    //  oauth_signature="8%2B4vXDHYJ3jiWuDvGB6VBKwfWkg%3D", 
    //  oauth_signature_method="HMAC-SHA1", 
    //  oauth_timestamp="1390526341", 
    //  oauth_token="320761140-hJzRG2P9aVtySOS5wLphS4EADm7RfY6NRmZKbvA3", 
    //  oauth_version="1.0" 
    using (WebClient client = new WebClient()) 
    { 
     client.Encoding = Encoding.UTF8; 
     client.Headers.Add(head); 
     try 
     { 
      client.UploadValues(target, method, data); 
      return @"Tweet Succeeded"; 
     } 
     catch (Exception e) 
     { 
      return @"Tweet Failed"; 
     } 
    } 
} 

是否有文本,可能导致问题的任何部件?如果不是,还有其他地方我应该看?如果需要特定的内容,我可以发布更多详细信息。

编辑:我已经断定这个问题是在某些有关的某些字符。例如,如果推文中有)(,则会失败。也就是说,带有哈希标签的推文(必须进行百分比编码)不会失败,因此与百分比编码没有直接关系。这一切似乎都很奇怪,因为Twitter OAuth工具和我们的程序都生成了完全相同的signature base stringsignature

编辑2:由于C#没有实现RFC 3986百分比编码,我们自己实现了它。不要特别认为这将最终被相关,但是,为了以防万一,在这里它是:

private static string PercentEncode(string input) 
{ 
    // List containing all byte values that don't need to be escaped. 
    // Source: https://dev.twitter.com/docs/auth/percent-encoding-parameters 
    byte[] nonEscaped = 
    { 
     // Digits 
     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 

     // Uppercase Letters 
     0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 
     0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 

     // Lowercase Letters 
     0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 
     0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 

     // Reserved Characters 
     0x2D, 0x2E, 0x5F, 0x7E 
    }; 

    byte[] bytes = Encoding.UTF8.GetBytes(input); 
    List<byte> output = new List<byte>(); 

    foreach (byte b in bytes) 
    { 
     if (nonEscaped.Contains(b)) 
     { 
      output.Add(b); 
     } 
     else 
     { 
      // add percent char 
      output.Add(0x25); 

      // encode first and last half of byte 
      int first = b & 0x0F; 
      int last = b >> 4; 
      output.Add(Convert.ToByte(last.ToString("X")[0])); 
      output.Add(Convert.ToByte(first.ToString("X")[0])); 
     } 
    } 

    return Encoding.UTF8.GetString(output.ToArray()); 
} 

回答

0

我们结束了在这段代码中揭露了两个问题。其中之一导致了所述问题。

第一个没有引起任何明显问题的问题是没有指定UTF-8字符编码的“Content-Type”标题。这看起来很小,并没有明显的问题。

的新的报头的值如下:

NameValueCollection head = new NameValueCollection 
         { 
          {"Authorization", oauth.GetHttpHeader(method, target, null, data)}, 
          {"Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"}, 
          {"User-Agent", "AgentX"} 
         }; 

更显著问题是WebClient是被允许百分之编码使用默认%的编码而不是RFC 3986该消息的主体中。通过将WebClient.UploadValues()更改为WebClient.UploadData()并手动创建要发送的字节,我们看到的问题已解决。