HttpPost работает в Java-проекте, а не в Android
Я написал код для моего Android-устройства для входа на веб-сайт поверх https
и разбора некоторых данных из результирующих страниц. HttpGet
происходит сначала, чтобы получить некоторую информацию, необходимую для входа в систему, а затем HttpPost
, чтобы выполнить фактический процесс входа в систему.
Этот код отлично работает в проекте Java в Eclipse, который имеет следующие файлы Jar на пути сборки: httpcore-4.1-beta2.jar
, httpclient-4.1-alpha2.jar
, httpmime-4.1-alpha2.jar
, commons-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, однако, если я запустил тот же самый код из проекта Android с 1,6 Android Jar файлом на пути сборки, я получаю ответ 200 с сервера. Я получаю тот же ответ 200 при запуске кода на моем устройстве 2.2.
У моего приложения Android есть разрешения на доступ к Интернету, и 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?
- Существуют ли другие, совершенно разные подходы к выполнению HttpPost в Android?
- Любые другие идеи?
Я читал a много сообщений и code, но я никуда не денусь. Я застрял на этом пару дней, и я в недоумении, как заставить дело работать, поэтому я попробую что-нибудь в этот момент. Спасибо заранее.
Ответы
Ответ 1
Теперь я отказался от получения маршрута HttpClient
, чтобы дать ожидаемый ответ от сервера при запуске на Android. Вместо этого я переписал выше описанный метод 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
не работал должным образом.
Ответ 2
чтобы избежать столкновений, используйте эту банку для httpclient
httplib
и этот пост также будет очень полезен
сообщение о переполнении стека
Ответ 3
Возможно ли, что этот сайт обнаруживает пользовательский агент и фактически возвращает разные результаты, потому что он Android? Учитывая, что 200 подразумевает успех, почему он должен давать 302 вместо 200? Вы распечатали результат, который вы получаете, когда он возвращает 200, и дает ли он дополнительную информацию?
Ответ 4
Проверьте RedirectHandler, переопределите значение по умолчанию и выполните некоторые записи в нем, у меня были проблемы с этим при переходе на Android...