HttpPost 适用于 Java 项目,不适用于 Android

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4221420/
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-30 05:22:51  来源:igfitidea点击:

HttpPost works in Java project, not in Android

javaandroidhttp-post

提问by dave.c

I've written some code for my Android device to login to a web site over httpsand parse some data out of the resulting pages. An HttpGethappens first to get some info needed for login, then an HttpPostto do the actual login process.

我已经为我的 Android 设备编写了一些代码来登录网站https并从结果页面中解析一些数据。一个HttpGet发生抢先拿到需要登陆一些信息,那么HttpPost做实际的登录过程。

The code below works great in a Java project within Eclipse which has the following Jar files on the build path: httpcore-4.1-beta2.jar, httpclient-4.1-alpha2.jar, httpmime-4.1-alpha2.jar, commons-logging-1.1.1.jar.

下面在Eclipse中的Java项目,具有构建路径上的下列JAR文件的伟大作品的代码:httpcore-4.1-beta2.jarhttpclient-4.1-alpha2.jarhttpmime-4.1-alpha2.jarcommons-logging-1.1.1.jar

public static MyBean gatherData(String username, String password) {
    MyBean myBean = new MyBean();
    try {
        HttpResponse response = doHttpGet(URL_PAGE_LOGIN, null, null);
        System.out.println("Got login page");
        String content = EntityUtils.toString(response.getEntity());
        String token = ContentParser.getToken(content);
        String cookie = getCookie(response);
        System.out.println("Performing login");
        System.out.println("token = "+token +" || cookie = "+cookie);
        response = doLoginPost(username,password,cookie, token);
        int respCode = response.getStatusLine().getStatusCode();
        if (respCode != 302) {
            System.out.println("ERROR: not a 302 redirect!: code is \""+ respCode+"\"");
            if (respCode == 200) {
                System.out.println(getHeaders(response));
                System.out.println(EntityUtils.toString(response.getEntity()).substring(0, 500));
            }
        } else {
            System.out.println("Logged in OK, loading account home");
            // redirect handler and rest of parse removed
        }
    }catch (Exception e) {
        System.out.println("ERROR in gatherdata: "+e.toString());
        e.printStackTrace();
    }
    return myBean;
}
private static HttpResponse doHttpGet(String url, String cookie, String referrer) {
    try {
        HttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");
        HttpGet httpGet = new HttpGet(url);
        httpGet.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        httpGet.setHeader(HEADER_USER_AGENT,HEADER_USER_AGENT_VALUE);
        if (referrer != null && !referrer.equals("")) httpGet.setHeader(HEADER_REFERER,referrer);
        if (cookie != null && !cookie.equals("")) httpGet.setHeader(HEADER_COOKIE,cookie);
        return client.execute(httpGet);
    } catch (Exception e) {
        e.printStackTrace();
        throw new ConnectException("Failed to read content from response");
    }
}
private static HttpResponse doLoginPost(String username, String password, String cookie, String token) throws ClientProtocolException, IOException {
    try {
        HttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");
        HttpPost post = new HttpPost(URL_LOGIN_SUBMIT);
        post.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        post.setHeader(HEADER_USER_AGENT,HEADER_USER_AGENT_VALUE);
        post.setHeader(HEADER_REFERER, URL_PAGE_LOGIN);
        post.setHeader(HEADER_COOKIE, cookie);
        post.setHeader("Content-Type","application/x-www-form-urlencoded");
        List<NameValuePair> formParams = new ArrayList<NameValuePair>();
        formParams.add(new BasicNameValuePair("org.apache.struts.taglib.html.TOKEN", token));
        formParams.add(new BasicNameValuePair("showLogin", "true"));
        formParams.add(new BasicNameValuePair("upgrade", ""));
        formParams.add(new BasicNameValuePair("username", username));
        formParams.add(new BasicNameValuePair("password", password));
        formParams.add(new BasicNameValuePair("submit", "Secure+Log+in"));
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams,HTTP.UTF_8);
        post.setEntity(entity);
        return client.execute(post);
    } catch (Exception e) {
        e.printStackTrace();
        throw new ConnectException("ERROR in doLoginPost(): "+e.getMessage());
    }
}

The server (which is not under my control) returns a 302 redirect when the login was successful, and 200 if it fails and re-loads the login page. When run with the above Jar files I get the 302 redirect, however if I run the exact same code from an Android project with the 1.6 Android Jar file on the build path I get the 200 response from the server. I get the same 200 response when running the code on my 2.2 device.

服务器(不受我控制)在登录成功时返回 302 重定向,如果失败并重新加载登录页面,则返回 200。使用上述 Jar 文件运行时,我得到 302 重定向,但是,如果我在构建路径上使用 1.6 Android Jar 文件从 Android 项目运行完全相同的代码,我会收到来自服务器的 200 响应。在我的 2.2 设备上运行代码时,我得到了相同的 200 响应。

My android application has internet permissions, and the HttpGet works fine. I'm assuming that the problem lies in the fact that HttpPost (or some other class) is different in some significant way between the Android Jar version and the newer Apache versions.

我的 android 应用程序具有互联网权限,并且 HttpGet 工作正常。我假设问题在于 HttpPost(或其他一些类)在 Android Jar 版本和较新的 Apache 版本之间在某些重要方面有所不同。

I've tried adding the Apache libraries to the build path of the Android project, but due to the duplicate classes I get messages like: INFO/dalvikvm(390): DexOpt: not resolving ambiguous class 'Lorg/apache/http/impl/client/DefaultHttpClient;'in the log. I've also tried using a MultipartEntityinstead of the UrlEncodedFormEntitybut I get the same 200 result.

我已经尝试将 Apache 库添加到 Android 项目的构建路径中,但由于类重复,我INFO/dalvikvm(390): DexOpt: not resolving ambiguous class 'Lorg/apache/http/impl/client/DefaultHttpClient;'在日志中收到如下消息。我也尝试使用 aMultipartEntity而不是 theUrlEncodedFormEntity但我得到了相同的 200 结果。

So, I have a few questions:
- Can I force the code running under android to use the newer Apache libraries in preference to the Android versions?
- If not, does anyone have any ideas how can I alter my code so that it works with the Android Jar?
- Are there any other, totally different approaches to doing an HttpPost in Android?
- Any other ideas?

所以,我有几个问题:
- 我可以强制在 android 下运行的代码优先使用较新的 Apache 库而不是 Android 版本吗?
- 如果没有,有没有人知道如何更改我的代码以使其适用于 Android Jar?
- 还有其他完全不同的方法可以在 Android 中执行 HttpPost 吗?
- 还有其他想法吗?

I've readalotofpostsand codebut I'm not getting anywhere. I've been stuck on this for a couple of days and I'm at a loss how to get the thing to work, so I'll try anything at this point. Thanks in advance.

一个很大职位代码,但我没有得到任何地方。我已经被困在这个问题上几天了,我不知道如何让它工作,所以我现在会尝试任何事情。提前致谢。

回答by dave.c

I have now given up on getting the HttpClientroute to give the expected response from the server when run on Android. Instead I rewrote the doPostmethod above to use an HttpsURLConnectioninstead. Here's the new (working) version in the hope that it's useful to someone.

我现在已经放弃了HttpClient在 Android 上运行时获取来自服务器的预期响应的路由。相反,我重写了doPost上面的方法以使用 anHttpsURLConnection代替。这是新的(工作)版本,希望它对某人有用。

private static LoginBean altPost(String username, String password, String cookie, String token){
    LoginBean loginBean = new LoginBean();
    HttpsURLConnection urlc = null;
    OutputStreamWriter out = null;
    DataOutputStream dataout = null;
    BufferedReader in = null;
    try {
        URL url = new URL(URL_LOGIN_SUBMIT);
        urlc = (HttpsURLConnection) url.openConnection();
        urlc.setRequestMethod("POST");
        urlc.setDoOutput(true);
        urlc.setDoInput(true);
        urlc.setUseCaches(false);
        urlc.setAllowUserInteraction(false);
        urlc.setRequestProperty(HEADER_USER_AGENT, HEADER_USER_AGENT_VALUE_FF);
        urlc.setRequestProperty("Cookie", cookie);
        urlc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
        String output = "org.apache.struts.taglib.html.TOKEN="+ URLEncoder.encode(token, HTTP.UTF_8)
                +"&showLogin=true&upgrade=&username="+ URLEncoder.encode(username, HTTP.UTF_8)
                +"&password="+ URLEncoder.encode(password, HTTP.UTF_8)+"&submit="
                +URLEncoder.encode("Secure+Log+in", HTTP.UTF_8);
        dataout = new DataOutputStream(urlc.getOutputStream());
        // perform POST operation
        dataout.writeBytes(output);
        // get response info
        loginBean.setResponseCode(urlc.getResponseCode());
        // get required headers
        String headerName = null;
        StringBuffer newCookie = new StringBuffer(100);
        String redirectLocation = "";
        for (int i=1; (headerName = urlc.getHeaderField(i)) != null;i++) {
            if (headerName.indexOf(COOKIE_VALUE_SESSION) > -1) {
                if (newCookie.length() > 0) {newCookie.append("; ");}
                newCookie.append(headerName);
            }
            if (headerName.indexOf(COOKIE_VALUE_AUTH) > -1) {
                if (newCookie.length() > 0) {newCookie.append("; ");}
                newCookie.append(headerName);
            }
            if (headerName.indexOf("https://") > -1) {
                redirectLocation = headerName;
            }
        }
        loginBean.setCookie(newCookie.toString());
        loginBean.setRedirectUrl(redirectLocation);

        in = new BufferedReader(new InputStreamReader(urlc.getInputStream()),8096);
        String response;
        // write html to System.out for debug
        while ((response = in.readLine()) != null) {
            System.out.println(response);
        }
        in.close();
    } catch (ProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return loginBean;
}

I still have no idea why the HttpClientway didn't work properly.

我仍然不知道为什么这种HttpClient方式不能正常工作。

回答by sunil shetty

to avoid the collisions use this jar for httpclient

为避免冲突,请将此 jar 用于 httpclient

httplib

httplib

and this post would also be very useful

这篇文章也非常有用

stack overflow post

堆栈溢出帖子

回答by Michael Aaron Safyan

Is it possible that this website does user-agent detection and actually returns different results because it's Android? Given that 200 implies success, why must it give a 302 instead of a 200? Have you printed out the result that you get when it returns a 200, and does it give any additional information?

这个网站是否有可能因为它是Android而进行用户代理检测并实际返回不同的结果?鉴于 200 意味着成功,为什么它必须给出 302 而不是 200?你有没有打印出返回 200 时得到的结果,它是否提供了任何额外的信息?

回答by dacwe

Check the RedirectHandler, override the default one and do some logging in it, I had problems with that when going to Android...

检查 RedirectHandler,覆盖默认设置并登录它,我在使用 Android 时遇到了问题...