0

我不明白,为什么我的 Twitter 阅读在我运行纯 Java 应用程序时有效,而在从 android java 程序调用时无效。我希望有一个人可以帮助我。我使用 twitter 的 1.1 API 的 application-authentification 方法。

我在执行 Java 时使用了以下代码,这是有效的:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;

import javax.net.ssl.HttpsURLConnection;

import org.apache.commons.codec.binary.Base64;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;



public class testSomething {

    private final static String getTokenURL = "https://api.twitter.com/oauth2/token";
    private static String bearerToken;

    public static final String CONSUMER_KEY = "<key>";
    public static final String CONSUMER_SECRET= "<secret>";

    /**
     * @param args
     */
    public static void main(String[] args) {

        // encodeKeys(APIKEY, APISECRET);

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {

                    bearerToken = requestBearerToken(getTokenURL);

                    System.out.println("Search = " + "https://api.twitter.com/1.1/search/tweets.json?q=%23PhuseKatja&count=20");
                    System.out.println("Bearer = " + bearerToken);

                    ArrayList<Tweet> tweets = fetchSearchTweet("https://api.twitter.com/1.1/search/tweets.json?q=%23PhuseKatja&count=20",
                                                               bearerToken);

                    System.out.println(tweets.size());

                } catch (IOException e) {
                    System.out.println("IOException e");
                    e.printStackTrace();
                }
            }
        }).start();

    }

    // Encodes the consumer key and secret to create the basic authorization key
    private static String encodeKeys(String consumerKey, String consumerSecret) {
        try {
            String encodedConsumerKey = URLEncoder.encode(consumerKey, "UTF-8");
            String encodedConsumerSecret = URLEncoder.encode(consumerSecret,
                    "UTF-8");

            String fullKey = encodedConsumerKey + ":" + encodedConsumerSecret;
            byte[] encodedBytes = Base64.encodeBase64(fullKey.getBytes());

            return new String(encodedBytes);
        } catch (UnsupportedEncodingException e) {
            return new String();
        }
    }

    // Constructs the request for requesting a bearer token and returns that
    // token as a string
    public static String requestBearerToken(String endPointUrl)
            throws IOException {
        HttpsURLConnection connection = null;
        String encodedCredentials = encodeKeys(CONSUMER_KEY, CONSUMER_SECRET);

        System.out.println("encodedCredentials "+encodedCredentials);
        try {
            URL url = new URL(endPointUrl);
            connection = (HttpsURLConnection) url.openConnection();
            System.out.println(connection);
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Host", "api.twitter.com");
            connection.setRequestProperty("User-Agent", "Android Phuse Application");
            connection.setRequestProperty("Authorization", "Basic " + encodedCredentials);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            connection.setRequestProperty("Content-Length", "29");
            connection.setUseCaches(false);

            writeRequest(connection, "grant_type=client_credentials");

            // Parse the JSON response into a JSON mapped object to fetch fields
            // from.
            JSONObject obj = (JSONObject) JSONValue.parse(readResponse(connection));

            if (obj != null) {
                String tokenType = (String) obj.get("token_type");
                String token = (String) obj.get("access_token");

                return ((tokenType.equals("bearer")) && (token != null)) ? token
                        : "";
            }
            return new String();
        } catch (MalformedURLException e) {
            throw new IOException("Invalid endpoint URL specified.", e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }


    // Fetches the first tweet from a given user's timeline
        public static ArrayList<Tweet> fetchSearchTweet(String endPointUrl, String aBearerToken)
                throws IOException {
            HttpsURLConnection connection = null;

            ArrayList<Tweet> tweets = new ArrayList<Tweet>();

            try {
                URL url = new URL(endPointUrl);
                connection = (HttpsURLConnection) url.openConnection();
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setRequestMethod("GET");
                connection.setRequestProperty("Host", "api.twitter.com");
                connection.setRequestProperty("User-Agent", "anyApplication");
                connection.setRequestProperty("Authorization", "Bearer " +  aBearerToken);
                connection.setUseCaches(false);

                String response = readResponse(connection);

                System.out.println("Response = " + response);
                System.out.println(connection.getResponseMessage());
                System.out.println(connection.getResponseCode());
                System.out.println("---------------------------------");

                // Parse the JSON response into a JSON mapped object to fetch fields from.
                JSONObject objSearch = (JSONObject) JSONValue.parse(response);
                JSONArray ja = (JSONArray) objSearch.get("statuses");

                if (ja != null) {
                    for (int i = 0; i < ja.size(); i++)
                    {
                        Tweet tweet = new Tweet((((JSONObject)((JSONObject) ja.get(i)).get("user")).get("screen_name").toString()), 
                                                ((JSONObject) ja.get(i)).get("text").toString(), 
                                                (((JSONObject)((JSONObject) ja.get(i)).get("user")).get("profile_image_url").toString()));
                        tweets.add(tweet);
                    }
                }
                return tweets;
            } catch (MalformedURLException e) {
                throw new IOException("Invalid endpoint URL specified.", e);
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }

    // Writes a request to a connection
    private static boolean writeRequest(HttpURLConnection connection,
            String textBody) {
        try {
            BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(
                    connection.getOutputStream()));
            wr.write(textBody);
            wr.flush();
            wr.close();

            return true;
        } catch (IOException e) {
            return false;
        }
    }

    // Reads a response for a given connection and returns it as a string.
    private static String readResponse(HttpURLConnection connection) {
        try {
            StringBuilder str = new StringBuilder();

            BufferedReader br = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line = "";
            while ((line = br.readLine()) != null) {
                str.append(line + System.getProperty("line.separator"));
            }
            return str.toString();
        } catch (IOException e) {
            return new String();
        }
    }

    public static class Tweet {
        public String username;
        public String message;
        public String image_url;
        //public Bitmap image_bitmap;

        public Tweet(String username, String message, String url) {
            this.username  = username;
            this.message   = message;
            this.image_url = url;

            //this.image_bitmap = getBitmap(url);
        }
    }
}

当我创建 Android Java 应用程序(我最终需要它)时,我可以调用相同的代码但它不起作用。我的 fetchSearchTweet 请求确实收到了 400“错误响应”代码。BearerToken 已按预期收到,并且在打印令牌和搜索字符串时,都是一样的。

对于 Android,我创建了一个完整的新项目,激活 Internet 连接,复制相同的 testSomething 类并尝试运行它。但不幸的是,这不起作用(twitter 响应 400)。我没有线索。

import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

        try {
            String bearerToken = testSomething.requestBearerToken("https://api.twitter.com/oauth2/token");
            testSomething.fetchSearchTweet("https://api.twitter.com/1.1/search/tweets.json?q=%23PhuseKatja&count=20", bearerToken);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

我使用了博客中的示例和有用的问题资源


这在 Android-Java 中不起作用的原因在于纯 Java 和 Android Java 不同的“HttpsURLConnection”类。不知道新的 Twitter API 是否不支持 Android 提供的 HttpsURLConnection 或者 Android 的 HttpsURLConnection 是否不符合要求的格式。

我现在正在使用Twitter4J的快照版本,它也支持应用程序身份验证模式。

4

2 回答 2

2

您不应该使用URLEncoder.encode您的密钥,因为之后它将在 Base64 中进行转换。简单地

return Base64.encodeToString((consumerKey + ":" + consumerSecret).getBytes(),
                    Base64.NO_WRAP);

在你的encodeKeys方法中。(我使用这种精确的方法并且没有问题。)

于 2013-07-19T07:57:55.650 回答
0

我知道这是一个旧线程,但是我注意到对此没有可接受的答案。寻找这个问题的答案将我引向@IgorGanapolsky 的评论。

NO_WRAP 是这里的关键。我正在使用 Base64.DEFAULT ,它在字符串中放置了换行符......

我收到来自 Twitter 的错误请求,没有错误消息,将标志更改为Base64.encodeBase64(fullKey.getBytes())NO_WRAP 使 Twitter 返回 200。

干杯

于 2016-12-14T01:38:48.477 回答