作爲項目需求的一部分,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 string
和signature
。
編輯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());
}