2013-06-21 4 views
4

Мы только что изменили на Twitter api 1.1, и теперь Tweeting не работает & возвращает ошибку «Удаленный сервер вернул ошибку: (400)« Плохой запрос ». Изучение SO об этом говорит о том, что это как-то связано с аутентификацией, но мы отправляем секретный ключ accessToken &, который мы только что получили на странице входа. Все это отлично работало с api 1.0. Код -Twitter Проблемы с POST с использованием api 1.1

public void Tweet(Action<string> response, string message) 
    { 
     StringBuilder sb = new StringBuilder(); 
     sb.Append("POST&"); 
     sb.Append(Uri.EscapeDataString(_postUrl)); 
     sb.Append("&"); 

     string oauthNonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString())); 
     string timeStamp = MakeTimestamp(); 

     var dict = new SortedDictionary<string, string> 
     { 
      { "oauth_consumer_key", _oAuthConfig.ConsumerKey }, 
      { "oauth_nonce", oauthNonce }, 
      { "oauth_signature_method", "HMAC-SHA1" }, 
      { "oauth_timestamp", timeStamp }, 
      { "oauth_token", _accessToken }, 
      { "oauth_version", "1.0" }, 
     }; 

     foreach (var keyValuePair in dict) 
     { 
      sb.Append(Uri.EscapeDataString(string.Format("{0}={1}&", keyValuePair.Key, keyValuePair.Value))); 
     } 

     string encodedMessage = EscapeAdditionalChars(Uri.EscapeDataString(message)); 
     sb.Append(Uri.EscapeDataString("status=" + encodedMessage)); 

     string signatureBaseString = sb.ToString(); 


     // create the signature 

     string signatureKey = Uri.EscapeDataString(_oAuthConfig.ConsumerSecret) + "&" + Uri.EscapeDataString(_accessTokenSecret); 

     var hmacsha1 = new HMACSHA1(new ASCIIEncoding().GetBytes(signatureKey)); 

     string signatureString = Convert.ToBase64String(hmacsha1.ComputeHash(new ASCIIEncoding().GetBytes(signatureBaseString))); 


     // create the headers 

     string authorizationHeaderParams = String.Empty; 

     authorizationHeaderParams += "OAuth "; 
     authorizationHeaderParams += "oauth_consumer_key=\"" + _oAuthConfig.ConsumerKey + "\", "; 
     authorizationHeaderParams += "oauth_nonce=\"" + oauthNonce + "\", "; 
     authorizationHeaderParams += "oauth_signature=\"" + Uri.EscapeDataString(signatureString) + "\", "; 
     authorizationHeaderParams += "oauth_signature_method=\"" + "HMAC-SHA1" + "\", "; 
     authorizationHeaderParams += "oauth_timestamp=\"" + timeStamp + "\", "; 
     authorizationHeaderParams += "oauth_token=\"" + _accessToken + "\", "; 
     authorizationHeaderParams += "oauth_version=\"" + "1.0" + "\""; 

     string messageToPost = EscapeAdditionalChars(SpacesToPlusSigns(message)); 


     // initialise the WebClient 

     WebClient client = new WebClient(); 

     client.Headers [HttpRequestHeader.Authorization] = authorizationHeaderParams; 

     client.UploadDataCompleted += (s, eArgs) => 
     { 
      if (eArgs.Error == null) 
       response(DefaultSuccessMessage()); 
      else 
       response(eArgs.Error.Message); 
     }; 

     try 
     { 
      Uri uri = new Uri(_postUrl); 
      try 
      { 
       client.UploadDataAsync(uri, "POST", Encoding.UTF8.GetBytes("status=" + messageToPost)); 
      } 
      catch (WebException e) 
      { 
       Log.Info("TwitterService->Tweet web error: " + e.Message); 
       response(DefaultErrorMessage()); 
      } 
      catch (Exception e) 
      { 
       // Can happen if we had already favorited this status 
       Log.Info("TwitterService->Tweet error: " + e.Message); 
       response(DefaultErrorMessage()); 
      } 
     } 
     catch (WebException e) 
     { 
      Log.Info("TwitterService->Tweet web error 2: " + e.Message); 
      response(DefaultErrorMessage()); 
     } 
     catch (Exception e) 
     { 
      Log.Info("TwitterService->Tweet error 2: " + e.Message); 
      response(DefaultErrorMessage()); 
     } 
    } 

В принципе, я хотел бы быть в состоянии Tweet без использования каких-либо 3-библиотек, таких как Twitterizer (даже TweetStation, кажется, сломано с API 1.1) - конечно, это не может быть, сложно!

Любая помощь очень ценится, так как он чувствует себя немного как кирпичная стена на данный момент - я также довольно новыми для C#, который не помогает ...

Edited показать код, который WASN» t ясно.

+0

Уверены, что вы не ограничены в скорости; Так как это также вызовет запрос 400/Bad. –

+0

Определенно не проблема ограничения скорости, и ошибка изменяется в зависимости от настроек, которые я делаю для кода, это может быть либо 400/Bad Request, либо 401/Unauthorized. Я, наконец, понял это - см. Мой ответ – SomaMan

ответ

-1

400 означает, что вы не прошли аутентификацию. Я рекомендую получить пользовательский контекст.

https://dev.twitter.com/docs/auth/oauth#user-context

+0

Я не думаю, что проблема аутентификации - это проблема, поскольку я только что подписал & получил доступ к Token & accessTokenSecret.Я думаю, что это могло бы быть чем-то связано с используемыми кодировками - я изучаю это. – SomaMan

0

Я столкнулся с этой проблемой, или, по крайней мере, один поразительный похож (с моей точки зрения нуба), в последнее время для приложения я в здании. Что, казалось, решило это для меня (после просмотра инструмента на dev.twitter.com) было просто избавиться от котировок вокруг имен параметров, так что (в вашем случае):

Я замечаю, что на самом деле у вас нет котировок вокруг имен ваших параметров. Тем не менее, это смущает меня, что вы дважды отправляете данные аутентификации (отсюда и мой неправильный пост). Это работает для меня, не делая этого, и я коротко искал его и нашел: https://dev.twitter.com/discussions/12322#comment-27120, что подтверждает, что это может быть проблемой, порождающей ошибку Autetication.

+0

Спасибо за ваше предложение - я, наконец, нашел решение, и я отправлю ответ, который детализирует все. На самом деле, в конце концов, ничего общего с кавычками, но стоит учесть - документы в Twitter не помогли (возможно, достаточно справедливо, так как в итоге это была проблема C#). – SomaMan

5

Наконец-то нашел решение, как обычно, с большинством из этих вещей, было довольно просто. Код ниже -

public void Tweet(Action<string> response, string message) 
    { 
     StringBuilder sb = new StringBuilder(); 
     sb.AppendFormat ("status={0}", PercentEncode(message)); 

     string content = sb.ToString(); 


     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_postUrl); 

     request.Headers.Add("Authorization", AuthorizeRequest(_accessToken, _accessTokenSecret, "POST", new Uri(_postUrl), content)); 
     request.ContentType = "application/x-www-form-urlencoded"; 
     request.ServicePoint.Expect100Continue = false; 
     request.Method = "POST"; 


     try 
     { 
      try 
      { 
       using (Stream stream = request.GetRequestStream()) 
       { 
        Byte[] streamContent = Encoding.UTF8.GetBytes("status=" + PercentEncode(message)); 
        stream.Write(streamContent, 0, streamContent.Length); 
       } 


       HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse(); 

       string contents = ""; 
       using (Stream stream = webResponse.GetResponseStream()) 
        using (StreamReader reader = new StreamReader(stream)) 
        { 
         contents = reader.ReadToEnd(); 
        } 

       Console.WriteLine("Twitter response: " + contents); 

       response(DefaultSuccessMessage()); 

      } 
      catch (WebException e) 
      { 
       Log.Info("TwitterService->Tweet web error: " + e.Message); 
       response(DefaultErrorMessage()); 
      } 
      catch (Exception e) 
      { 
       // Can happen if we had already favorited this status 
       Log.Info("TwitterService->Tweet error: " + e.Message); 
       response(DefaultErrorMessage()); 
      } 
     } 
     catch (WebException e) 
     { 
      Log.Info("TwitterService->Tweet web error 2: " + e.Message); 
      response(DefaultErrorMessage()); 
     } 
     catch (Exception e) 
     { 
      Log.Info("TwitterService->Tweet error 2: " + e.Message); 
      response(DefaultErrorMessage()); 
     } 
    } 


    private string AuthorizeRequest(string oauthToken, string oauthTokenSecret, string method, Uri uri, string data) 
    { 
     string oauthNonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString())); 

     var headers = new Dictionary<string, string>() 
     { 
      { "oauth_consumer_key", _oAuthConfig.ConsumerKey }, 
      { "oauth_nonce", oauthNonce }, 
      { "oauth_signature_method", "HMAC-SHA1" }, 
      { "oauth_timestamp", MakeTimestamp() }, 
      { "oauth_token", oauthToken }, 
      { "oauth_verifier", PercentEncode(_authorizationVerifier) }, 
      { "oauth_version", "1.0A" } 
     }; 
     var signatureHeaders = new Dictionary<string,string>(headers); 

     // Add the data and URL query string to the copy of the headers for computing the signature 
     if (data != null && data != "") 
     { 
      var parsed = HttpUtility.ParseQueryString(data); 
      foreach (string k in parsed.Keys) 
      { 
       signatureHeaders.Add(k, PercentEncode(parsed [k])); 
      } 
     } 

     var nvc = HttpUtility.ParseQueryString(uri.Query); 
     foreach (string key in nvc) 
     { 
      if (key != null) 
       signatureHeaders.Add(key, PercentEncode(nvc [key])); 
     } 

     string signature = MakeSignature (method, uri.GetLeftPart(UriPartial.Path), signatureHeaders); 
     string compositeSigningKey = MakeSigningKey(_oAuthConfig.ConsumerSecret, oauthTokenSecret); 
     string oauth_signature = MakeOAuthSignature(compositeSigningKey, signature); 

     headers.Add ("oauth_signature", PercentEncode(oauth_signature)); 


     return HeadersToOAuth(headers); 
    } 


    private static string PercentEncode (string s) 
    { 
     var sb = new StringBuilder(); 

     foreach (byte c in Encoding.UTF8.GetBytes (s)) 
     { 
      if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~') 
       sb.Append ((char) c); 
      else 
      { 
       sb.AppendFormat ("%{0:X2}", c); 
      } 
     } 
     return sb.ToString(); 
    } 


    private static string MakeTimestamp() 
    { 
     return ((long) (DateTime.UtcNow - _unixBaseTime).TotalSeconds).ToString(); 
    } 

    private static string MakeSignature (string method, string base_uri, Dictionary<string,string> headers) 
    { 
     var items = from k in headers.Keys orderby k 
      select k + "%3D" + PercentEncode (headers [k]); 

     return method + "&" + PercentEncode (base_uri) + "&" + 
      string.Join ("%26", items.ToArray()); 
    } 

    private static string MakeSigningKey (string consumerSecret, string oauthTokenSecret) 
    { 
     return PercentEncode (consumerSecret) + "&" + (oauthTokenSecret != null ? PercentEncode (oauthTokenSecret) : ""); 
    } 

    private static string MakeOAuthSignature (string compositeSigningKey, string signatureBase) 
    { 
     var sha1 = new HMACSHA1 (Encoding.UTF8.GetBytes (compositeSigningKey)); 

     return Convert.ToBase64String (sha1.ComputeHash (Encoding.UTF8.GetBytes (signatureBase))); 
    } 

    private static string HeadersToOAuth (Dictionary<string,string> headers) 
    { 
     return "OAuth " + String.Join (",", (from x in headers.Keys select String.Format ("{0}=\"{1}\"", x, headers [x])).ToArray()); 
    } 

С Twitter API 1.0, я использовал WebClient к сообщению, которое не работает с API 1.1, и кажется, что причина этого заключается в том, что вы не можете установить ContentType или Свойства ServicePoint.Expect100Continue - без этих параметров, как я их установил, запрос отправляется как (401) несанкционированным. В конце концов, проблемы с кодированием не связаны.

Спасибо другим за различные вспомогательные методы.

+0

Я потратил большую часть целого дня, пытаясь заставить работать аутентификацию. Это боль в $$. Это было в значительной степени копирование + вставка. Благодарю. Я не мог больше догадываться, что случилось! – Dave

3

У меня была точно такая же проблема:

Это именно то, что вам нужно сделать здесь:

Authenticate and request a user's timeline with Twitter API 1.1 oAuth

Я создал проект для этого на: https://github.com/andyhutch77/oAuthTwitterTimeline

Она также включает демонстрацию MVC, веб-приложения и консоли.

+0

Спасибо за публикацию, но я уже понял это и опубликовал мое решение! Не могу подумать, как я не столкнулся со своим сообщением, когда искал, и долго искал ... – SomaMan

+0

Нет проблем, возможно, до того, как я разместил это тоже. – hutchonoid

Смежные вопросы