【问题标题】:HttpPost works in Java project, but not on AndroidHttpPost 适用于 Java 项目,但不适用于 Android
【发布时间】:2011-05-12 09:47:30
【问题描述】:

我为我的 Android 设备编写了一些代码,用于通过 HTTPS 登录网站并从结果页面中解析出一些数据。 HttpGet 首先是获取登录所需的一些信息,然后是 HttpPost 进行实际的登录过程。

以下代码在 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());
    }
}

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

我的 android 应用程序具有 Internet 权限,并且 HttpGet 工作正常。我假设问题在于 HttpPost(或其他类)在 Android JAR 版本和较新的 Apache 版本之间存在某种显着差异。

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

所以,我有几个问题:

  • 我可以强制在 Android 下运行的代码使用较新的 Apache 库而不是 Android 版本吗?
  • 如果没有,是否有人知道如何更改我的代码以使其适用于 Android JAR 文件?
  • 还有其他完全不同的方法可以在 Android 中执行 HttpPost 吗?
  • 还有其他想法吗?

我有 read a lot of postscode,但我什么都没有。

【问题讨论】:

    标签: java android http-post


    【解决方案1】:

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

    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;
    }
    

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

    【讨论】:

    • 好答案。在 Gingerbread 及以后, HttpURLConnection 是要走的路。考虑弃用 Apache HttpClient。
    【解决方案2】:

    为避免冲突,请将此 JAR 文件用于 httpclient:

    httplib

    而且这篇文章也很有用:

    An answer to Stack Overflow question Apache HTTP client or URLConnection

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 200 结果只是用户再次登录页面,没有错误消息或其他信息,这是错误登录通常会发生的情况。我在标头中明确设置用户代理,并且无论以何种方式调用代码,它的设置都是相同的。我可以从我的 android 手机上的浏览器登录到该网站,这意味着它没有阻止基于它的 android 的事实。
      【解决方案4】:

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

      【讨论】:

      • 我对重定向代码(我没有在上面包含)相当满意,问题是我什至没有走那么远。由于服务器从 Android 返回 200 代码而不是从 Eclipse 返回的 302,因此我没有到达需要处理重定向的部分。
      • 哼,会不会是用户代理的问题?
      • 用户代理在上面的代码中设置,无论是在Android中运行还是作为纯Java运行,都设置为相同的值。我尝试了一个 android 用户代理、一个 FF/windows 和一些自定义的。它们都给出相同的行为。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-24
      • 1970-01-01
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      • 2019-03-16
      • 1970-01-01
      相关资源
      最近更新 更多