2014-01-24 68 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()並手動創建要發送的字節,我們看到的問題已解決。