我在Flutter应用程序中调用Twitter api时遇到麻烦。我已经使用Twitter登录库获取我的令牌和秘密令牌,并且我有我的消费者和消费者秘密。但是我无法正确形成一个https请求。我尝试过使用Oauth2客户端以及直接请求,但都没有用。
我使用dart 1 Twitter和Oauth实现找到了此存储库,但是我一直无法弄清楚如何将其转换为Dart2。感谢所有帮助。
编辑:这是最新的代码:
final response = await http.get(new Uri.https( "api.twitter.com", "/1.1/statuses/home_timeline.json", { "count": "200", "tweet_mode": "extended", "exclude_replies": "false" }), headers: { "Authorization": 'Bearer ${twitter.token}', //twitter.token is the token recieved from Twitter sign in process "Content-Type": "application/json" });
返回"errors":[{"code":89,"message":"Invalid or expired token."}] 我知道令牌是有效的
"errors":[{"code":89,"message":"Invalid or expired token."}]
编辑2:
Future<List<Tweet>> getTimeline() async { print("Getting timeline"); var query = https.get( "https://api.twitter.com/1.1/statuses/home_timeline.json?count=2&tweet_mode=extended&exclude_replies=false", headers: { "Authorization": 'oauth_consumer_key="$_consumerKey", oauth_token="${twitter.token}"', "Content-Type": "application/json" }).timeout(Duration(seconds: 15)); print("Before await"); final response = await query; print("code: ${response.statusCode}"); ... }
经过更多调试后,twitter.token可能会出现空异常。解决此问题后,我仍然收到错误的授权数据。我将继续尝试向标题添加更多信息,并查看是否有帮助。
编辑3:
这是我的生成签名方法:
static String generateSignature(String method, String base, List<String> sortedItems) { String sig = '$method&${Uri.encodeComponent(base)}&'; String param = ''; for (int i = 0; i < sortedItems.length; i++) { if (i == 0) param = sortedItems[i]; else param += '&${sortedItems[i]}'; } sig += Uri.encodeComponent(param); String key = '${Uri.encodeComponent(_secretKey)}&${Uri.encodeComponent(twitter.secret)}'; var digest = Hmac(sha1, utf8.encode(key)).convert(utf8.encode(sig)); print("base: ${digest.bytes}"); print("sig: ${base64.encode(digest.bytes)}"); return base64.encode(digest.bytes); }
这是时间轴方法:
Future<List<Tweet>> getTimeline() async { print("Getting timeline"); Future<http.Response> query; try { String base = 'https://api.twitter.com/1.1/statuses/home_timeline.json'; String count = 'count=2'; String mode = 'tweet_mode=extended'; String replies = 'exclude_replies=false'; String oauthConsumer = 'oauth_consumer_key="$_consumerKey"'; String oauthToken = 'oauth_token="${twitter.token}"'; String oauthNonce = 'oauth_nonce="${randomAlphaNumeric(20)}"'; String oauthVersion = 'oauth_version="1.0"'; String oauthTime = 'oauth_timestamp="${DateTime.now().millisecondsSinceEpoch}"'; String oauthMethod = 'oauth_signature_method="HMAC-SHA1"'; String oauthSig = 'oauth_signature="${generateSignature("GET", base, [ count, replies, oauthConsumer, oauthNonce, oauthTime, oauthToken, oauthVersion, mode ])}"'; query = http.get( new Uri.https("api.twitter.com", "/1.1/statuses/home_timeline.json", { "count": "2", "tweet_mode": "extended", "exclude_replies": "false" }), headers: { "Authorization": '$oauthConsumer, $oauthToken, $oauthVersion, $oauthTime, $oauthNonce, $oauthMethod, $oauthSig', "Content-Type": "application/json" }).timeout(Duration(seconds: 15)); } catch (e) { print(e); }
谢谢!
这是最终工作的代码:
生成字符串方法:
static String generateSignature( String method, String base, List<String> sortedItems) { String param = ''; for (int i = 0; i < sortedItems.length; i++) { if (i == 0) param = sortedItems[i]; else param += '&${sortedItems[i]}'; } String sig = '$method&${Uri.encodeComponent(base)}&${Uri.encodeComponent(param)}'; String key = '${Uri.encodeComponent(_secretKey)}&${Uri.encodeComponent(twitter.secret)}'; var digest = Hmac(sha1, utf8.encode(key)).convert(utf8.encode(sig)); return base64.encode(digest.bytes); }
Twitter接听电话的便捷方法:
Future<http.Response> _twitterGet( String base, List<List<String>> params) async { if (twitter == null) await _startSession(); String oauthConsumer = 'oauth_consumer_key="${Uri.encodeComponent(_consumerKey)}"'; String oauthToken = 'oauth_token="${Uri.encodeComponent(twitter.token)}"'; String oauthNonce = 'oauth_nonce="${Uri.encodeComponent(randomAlphaNumeric(42))}"'; String oauthVersion = 'oauth_version="${Uri.encodeComponent("1.0")}"'; String oauthTime = 'oauth_timestamp="${(DateTime.now().millisecondsSinceEpoch / 1000).toString()}"'; String oauthMethod = 'oauth_signature_method="${Uri.encodeComponent("HMAC-SHA1")}"'; var oauthList = [ oauthConsumer.replaceAll('"', ""), oauthNonce.replaceAll('"', ""), oauthMethod.replaceAll('"', ""), oauthTime.replaceAll('"', ""), oauthToken.replaceAll('"', ""), oauthVersion.replaceAll('"', "") ]; var paramMap = Map<String, String>(); for (List<String> param in params) { oauthList.add( '${Uri.encodeComponent(param[0])}=${Uri.encodeComponent(param[1])}'); paramMap[param[0]] = param[1]; } oauthList.sort(); String oauthSig = 'oauth_signature="${Uri.encodeComponent(generateSignature("GET", "https://api.twitter.com$base", oauthList))}"'; return await http .get(new Uri.https("api.twitter.com", base, paramMap), headers: { "Authorization": 'Oauth $oauthConsumer, $oauthNonce, $oauthSig, $oauthMethod, $oauthTime, $oauthToken, $oauthVersion', "Content-Type": "application/json" }).timeout(Duration(seconds: 15)); }
示例调用:
Future<User> getUser(String tag) async { String base = '/1.1/users/show.json'; final response = await _twitterGet(base, [ ["screen_name", tag], ["tweet_mode", "extended"] ]); if (response.statusCode == 200) { try { return User(json.decode(response.body)); } catch (e) { print(e); return null; } } else { print("Error retrieving user"); print(response.body); return null; } }