作为项目需求的一部分,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());
}