java Android:HttpURLConnection 无法正常工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12693138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 09:50:51  来源:igfitidea点击:

Android: HttpURLConnection not working properly

javaandroidhttpurlconnection

提问by giorgiline

I'm trying to get the cookies from a website after sending user credentials through a POST Request an it seems that it doesn't work in android this way. ?Am I doing something bad?. Please help. I've searched here in different posts but there's no useful answer.

在通过 POST 请求发送用户凭据后,我试图从网站获取 cookie,但这种方式在 android 中似乎不起作用。?我在做坏事吗?。请帮忙。我在不同的帖子中在这里搜索过,但没有有用的答案。

It's curious that this run in a desktop Java implementation it works perfect but it crashes in Android platform. And it is exactly the same code, specifically when calling HttpURLConnection.getHeaderFields(), it also happens with other member methods. It's a simple code and I don't know why the hell isn't working.

奇怪的是,这在桌面 Java 实现中运行它运行完美,但它在 Android 平台上崩溃。它是完全相同的代码,特别是在调用 HttpURLConnection.getHeaderFields() 时,其他成员方法也会发生这种情况。这是一个简单的代码,我不知道为什么它不起作用。

DESKTOP CODE: This goes just in the main()

桌面代码:这只是在 main()

HttpURLConnection connection = null;
        OutputStream out = null;
        try {                   
            URL url = new URL("http://www.XXXXXXXX.php");           
            String charset = "UTF-8";       

            String postback = "1";
            String user = "XXXXXXXXX";
            String password = "XXXXXXXX";
            String rememberme = "on";
            String query = String.format("postback=%s&user=%s&password=%s&rememberme=%s"
                    , URLEncoder.encode(postback, charset)
                    , URLEncoder.encode(user,charset)
                    , URLEncoder.encode(password, charset)
                    , URLEncoder.encode(rememberme, charset));

            connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept-Charset", charset);
            connection.setDoOutput(true);           
            connection.setFixedLengthStreamingMode(query.length());

            out = connection.getOutputStream ();
            out.write(query.getBytes(charset));

            if (connection.getHeaderFields() == null){
                System.out.println("Header null");
            }else{
                for (String cookie: connection.getHeaderFields().get("Set-Cookie")){
                    System.out.println(cookie.split(";", 2)[0]);
                }
            }
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            try { out.close();} catch (IOException e) { e.printStackTrace();}
            connection.disconnect();            
        }

So the output is:

所以输出是:

    login_key=20ad8177db4eca3f057c14a64bafc2c9
    FASID=cabf20cc471fcacacdc7dc7e83768880
    track=30c8183e4ebbe8b3a57b583166326c77
    client-data=%7B%22ism%22%3Afalse%2C%22showm%22%3Afalse%2C%22ts%22%3A1349189669%7D

ANDROID CODE: This goes inside doInBackground AsyncTask body

ANDROID 代码:这在 doInBackground AsyncTask 主体中

HttpURLConnection connection = null;
            OutputStream out = null;
            try {                   
                URL url = new URL("http://www.XXXXXXXXXXXXXX.php");         
                String charset = "UTF-8";       

                String postback = "1";
                String user = "XXXXXXXXX";
                String password = "XXXXXXXX";
                String rememberme = "on";
                String query = String.format("postback=%s&user=%s&password=%s&rememberme=%s"
                        , URLEncoder.encode(postback, charset)
                        , URLEncoder.encode(user,charset)
                        , URLEncoder.encode(password, charset)
                        , URLEncoder.encode(rememberme, charset));

                connection = (HttpURLConnection)url.openConnection();
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Accept-Charset", charset);
                connection.setDoOutput(true);           
                connection.setFixedLengthStreamingMode(query.length());

                out = connection.getOutputStream ();
                out.write(query.getBytes(charset));

                if (connection.getHeaderFields() == null){
                    Log.v(TAG, "Header null");
                }else{
                    for (String cookie: connection.getHeaderFields().get("Set-Cookie")){
                        Log.v(TAG, cookie.split(";", 2)[0]);
                    }
                }
            } catch (IOException e){
                e.printStackTrace();
            } finally {
                try { out.close();} catch (IOException e) { e.printStackTrace();}
                connection.disconnect();            
            }

And here there is no output, it seems that connection.getHeaderFields() doesn't return result. It takes al least 30 seconds to show the Log:

这里没有输出,似乎 connection.getHeaderFields() 没有返回结果。显示日志至少需要 30 秒:

10-02 16:56:25.918: V/class com.giorgi.myproject.activities.HomeActivity(2596): Header null

TESTED ON A GALAXY NEXUS

在 GALAXY NEXUS 上测试

回答by giorgiline

I've figured out what was the problem. It seems that using Java Desktop, the flag FollowRedirects is false by default (I suppose) and in Android it is true. getInstanceFollowRedirects is TRUE in both cases, so I don't really know why it works in a different way, but nevermind, the solution is perfect.

我已经弄清楚是什么问题了。似乎使用 Java 桌面,FollowRedirects 标志默认为 false (我想),而在 Android 中它是 true。getInstanceFollowRedirects 在这两种情况下都是 TRUE,所以我真的不知道为什么它以不同的方式工作,但没关系,解决方案是完美的。

So it wasn't capturing the response of the POST request, it was following some redirection and trying to get the response from another GET auto request.

所以它没有捕获 POST 请求的响应,而是遵循一些重定向并尝试从另一个 GET 自动请求获取响应。

The solution was to do: connection.setInstanceFollowRedirects(false);

解决方案是这样做: connection.setInstanceFollowRedirects(false);



The way I could know this was looking into the network traffic using a network monitor:

我知道这是使用网络监视器查看网络流量的方式:

From the Desktop application it was monitored this traffic:

从桌面应用程序监控此流量:

23  10:08:50 03/10/2012 1.3944670   javaw.exe   192.168.1.36    www.XXXXXXXXX.com   HTTP    HTTP:Request, POST /es/login.php    {HTTP:8, TCP:7, IPv4:6}
24  10:08:50 03/10/2012 1.3954741   javaw.exe   192.168.1.36    www.XXXXXXXXX.com   HTTP    HTTP:HTTP Payload, URL: /es/login.php   {HTTP:8, TCP:7, IPv4:6}
32  10:08:50 03/10/2012 1.9811257   javaw.exe   www.XXXXXXXXX.com   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:8, TCP:7, IPv4:6}

To monitor the traffic in Android application I had to run it in the emulator instead the phone.The result was:

为了监控 Android 应用程序中的流量,我不得不在模拟器而不是手机中运行它。结果是:

60  9:59:34 03/10/2012  4.0285909   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, POST /es/login.php    {HTTP:13, TCP:12, IPv4:11}
65  9:59:34 03/10/2012  4.1524735   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:HTTP Payload, URL: /es/login.php   {HTTP:13, TCP:12, IPv4:11}
75  9:59:35 03/10/2012  4.6276286   emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:13, TCP:12, IPv4:11}
77  9:59:35 03/10/2012  4.7095994   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, GET /es/login.php, Query:FASID=a5e39f35325499e060f43d35bc956a45   {HTTP:13, TCP:12, IPv4:11}
311 9:59:55 03/10/2012  24.8355823  emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:13, TCP:12, IPv4:11}
313 9:59:55 03/10/2012  24.9384843  emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, GET /es/main.html, Query:FASID=a5e39f35325499e060f43d35bc956a45   {HTTP:13, TCP:12, IPv4:11}
317 9:59:55 03/10/2012  25.0535818  emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:HTTP Payload, URL: /es/main.html   {HTTP:13, TCP:12, IPv4:11}

So, after applying the **connection.setInstanceFollowRedirects(false);**the result was the expected:

所以,在应用后**connection.setInstanceFollowRedirects(false);**,结果是预期的:

61  10:30:43 03/10/2012 4.9211205   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, POST /es/login.php    {HTTP:14, TCP:13, IPv4:12}
64  10:30:43 03/10/2012 5.0362501   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:HTTP Payload, URL: /es/login.php   {HTTP:14, TCP:13, IPv4:12}
70  10:30:43 03/10/2012 5.5103384   emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:14, TCP:13, IPv4:12}


Thank you for all your answers and interest.

感谢您的所有回答和兴趣。

回答by Emil Davtyan

It is probably something with the networking trying opening the address you are requesting in the mobile browser of the emulator or phone.

这可能与网络尝试打开您在模拟器或手机的移动浏览器中请求的地址有关。

回答by Bradsta

Make sure you've added the required permissions in the AndroidManifest.xml file.

确保您已在 AndroidManifest.xml 文件中添加了所需的权限。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

回答by Kevin Rave

I had a lot of trouble with HTTPURLConnectionAfter trying for a couple days, I found out, the order of setting headers matters. Here is what worked for me.

我遇到了很多麻烦HTTPURLConnection经过几天的尝试后,我发现设置标题的顺序很重要。这对我有用。

            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Host", "yoursite.com");
            conn.setRequestProperty("Authorization", "Basic " + Base64.encodeToString(toencode, Base64.DEFAULT));
            conn.setRequestProperty("Accept-Charset", "UTF-8");

            conn.setConnectTimeout (5000) ; 
            conn.setDoOutput(true); 
            conn.setDoInput(true); 

It should work for you.

它应该适合你。