您的位置:首页 > 理论基础 > 计算机网络

android 登录Javaeye(使用HttpURLConnection和HttpClient)

2011-12-12 15:17 423 查看
之前在网上看过好多人用java写登录网站,这次正好学习android,自己写实习一个,就拿经常登录的javaeye(现在叫iteye,已经是csdn的了)试一下。

先来分析javaeye登录界面



查看源文件

<form action="/login" id="login_form" method="post">            <table border="0" cellspacing="0" cellpadding="0" class="table_1">
<colgroup><col width="60" /><col /></colgroup>
<tr>
<th>账号</th>
<td>
<input class="input_1 required" id="user_name" name="name" placeholder="用户名或邮箱" tabindex="1" type="text" value="" />
</td>
</tr>
<tr>
<th>密码</th>
<td>
<input class="input_1 required" id="password" name="password" tabindex="2" type="password" value="" /></td>
</tr>
<tr>
<th> </th>
<td>
<input id="auto" name="remember_me" tabindex="3" type="checkbox" value="1" />
<label for="auto">下次自动登录</label>
<a href="/users/forget">忘记密码?</a>
</td>
</tr>
<tr>
<th> </th>
<td><input type="submit" name="button" id="button" value="登 录" class="btn_1 submit" tabindex="4" /></td>
</tr>
</table>
</form>


可以分析出post地址为http://www.iteye.com/login,账号是name、密码是password。

登录以后,使用chrome的开发人员工具(其他浏览器也有相关工具,我就不一一说了)拦截获取响应消息



可以看出返回的是302地址重定向



还需要注意的是每次提交时,不能遗漏的cookie即seesion_id ,javaeye用的是_javaeye3_session

接下来是我做的android的例子,使用webview控件,它只负责内容展现,请求响应我分别使用了HttpURLConnection和HttpClient。

不说了,上代码:

主布局main.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/textViewInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"/>

<WebView
android:id="@+id/webViewInfo"
android:layout_width="match_parent"
android:layout_height="260dp"
android:layout_below="@+id/textViewInfo"
android:layout_marginTop="30dp"
android:layout_alignParentLeft="true" />

<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/linearLayout1"
android:layout_alignParentLeft="true" >
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="使用Java" />

<Button
android:id="@+id/buttonJavaLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/textView2"
android:text="登录ITeye" />

<Button
android:id="@+id/buttonJavaMyMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/buttonJavaLogin"
android:text="ITeye收件箱" />
</LinearLayout>

<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="使用Apache" />

<Button
android:id="@+id/buttonApacheLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/textView1"
android:text="登录ITeye" />

<Button
android:id="@+id/buttonApacheMyMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/buttonApacheLogin"
android:text="ITeye收件箱" />
</LinearLayout>

</RelativeLayout>


登录对话框布局login.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="账号: " />

<EditText
android:id="@+id/editTextUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />

</LinearLayout>

<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密码: " />

<EditText
android:id="@+id/exitTextPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textPassword" />

</LinearLayout>

</LinearLayout>


AndroidManifest.xml不要忘了加如下代码:

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


主程序代码如下:

package com.zhang.test08_16;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class Test08_16Activity extends Activity {

private TextView textViewInfo;
private WebView webViewInfo;
private Button buttonJavaLogin;
private Button buttonJavaMyMessage;
private Button buttonApaceLogin;
private Button buttonApacheMyMessage;

private View loginView;
private AlertDialog loginDialog;
private EditText editTextUserName;
private EditText editTextPassword;

private String clientType;
private DefaultHttpClient client;
private String cookie;

private static final String LOGIN_URL = "http://www.iteye.com/login";
private static final String MESSAGE_URL = "http://app.iteye.com/messages";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

textViewInfo = (TextView)findViewById(R.id.textViewInfo);
webViewInfo = (WebView)findViewById(R.id.webViewInfo);
buttonJavaLogin = (Button)findViewById(R.id.buttonJavaLogin);
buttonJavaMyMessage = (Button)findViewById(R.id.buttonJavaMyMessage);
buttonApaceLogin = (Button)findViewById(R.id.buttonApacheLogin);
buttonApacheMyMessage = (Button)findViewById(R.id.buttonApacheMyMessage);

LayoutInflater inflater = LayoutInflater.from(this);
loginView = inflater.inflate(R.layout.login, null);
editTextUserName = (EditText) loginView.findViewById(R.id.editTextUsername);
editTextPassword = (EditText) loginView.findViewById(R.id.exitTextPassword);
loginDialog = getLoginDialog();

buttonJavaLogin.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
clientType = "java";
loginDialog.show();
}
});
buttonJavaMyMessage.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
showMyMessageJava();
}
});

buttonApaceLogin.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
clientType = "apache";
loginDialog.show();
}
});
buttonApacheMyMessage.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
showMyMessageApache();
}
});
}

@Override
protected void onResume() {
client = new DefaultHttpClient();//client.getCookieStore().getCookies()  session_id
HttpParams httpParams = client.getParams();
httpParams.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);

super.onResume();
}

@Override
protected void onPause() {
client.getConnectionManager().shutdown();

super.onPause();
}

private AlertDialog getLoginDialog() {
return new AlertDialog.Builder(Test08_16Activity.this)
.setTitle("登录")
.setView(loginView)
.setPositiveButton("登录", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
if (clientType.equals("apache")) {
loginApache();
} else if(clientType.equals("java")) {
loginJava();
}
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create();
}

private void loginJava() {
String username = editTextUserName.getText().toString();
String password = editTextPassword.getText().toString();

URL url = null;
try {
url = new URL(LOGIN_URL);
} catch (MalformedURLException e) {
}

HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
textViewInfo.setText(e.getMessage());
return;
}
try {
urlConnection.setRequestMethod("POST");
} catch (ProtocolException e) {
}
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestProperty("Connection", "keep-alive");
urlConnection.setInstanceFollowRedirects(false);//

OutputStream out = null;
try {
out = new BufferedOutputStream(urlConnection.getOutputStream());//请求
} catch (IOException e) {
urlConnection.disconnect();
textViewInfo.setText(e.getMessage());
return;
}

Writer writer = null;
try {
writer = new OutputStreamWriter(out,"UTF-8");
} catch (UnsupportedEncodingException e1) {
}
try {
writer.write("name="+username +"&password="+password);
} catch (IOException e) {
urlConnection.disconnect();
textViewInfo.setText(e.getMessage());
return;
} finally{
try {
writer.flush();
writer.close();
} catch (IOException e) {
}
}

getResponseJava(urlConnection);
}

private void showMyMessageJava() {
URL url = null;
try {
url = new URL(MESSAGE_URL);
} catch (MalformedURLException e) {
}

HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
textViewInfo.setText(e.getMessage());
return;
}
//method  The default value is "GET"

getResponseJava(urlConnection);
}

//共用HttpClient
private void loginApache() {
String username = editTextUserName.getText().toString();
String password = editTextPassword.getText().toString();

List<NameValuePair> params = new ArrayList<NameValuePair>(1);
params.add(new BasicNameValuePair("name", username));
params.add(new BasicNameValuePair("password", password));
HttpEntity formEntity = null;
try {
formEntity = new UrlEncodedFormEntity(params,HTTP.UTF_8);
} catch (UnsupportedEncodingException e) {
}

HttpPost request = new HttpPost(LOGIN_URL);
request.setEntity(formEntity);

getResponseApache(request);
}

private void showMyMessageApache() {
HttpGet request = new HttpGet(MESSAGE_URL);
getResponseApache(request);
}

private void getResponseJava(HttpURLConnection urlConnection) {
if(cookie != null) {//session_id
urlConnection.setRequestProperty("Cookie", cookie);
}

InputStream in = null;
try {
in = new BufferedInputStream(urlConnection.getInputStream());//响应
} catch (IOException e) {
urlConnection.disconnect();
textViewInfo.setText(e.getMessage());
return;
}

cookie = urlConnection.getHeaderField("Set-Cookie");//session_id
int responseCode = -1;
try {
responseCode = urlConnection.getResponseCode();
} catch (IOException e) {
urlConnection.disconnect();
textViewInfo.setText(e.getMessage());
return;
}
if(responseCode == 301 || responseCode == 302 || responseCode == 307) {//重定向
String location = urlConnection.getHeaderField("location");
URL url = null;
try {
url = new URL(location);
} catch (MalformedURLException e) {
}

HttpURLConnection urlConnectionRedirect = null;
try {
urlConnectionRedirect = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
textViewInfo.setText(e.getMessage());
return;
}

getResponseJava(urlConnectionRedirect);
return;
}

BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(in,"UTF-8"));
} catch (UnsupportedEncodingException e1) {
}
StringBuilder result = new StringBuilder();
String tmp = null;
try {
while((tmp = reader.readLine()) != null){
result.append(tmp);
}
} catch (IOException e) {
textViewInfo.setText(e.getMessage());
return;
} finally {
try {
reader.close();
urlConnection.disconnect();
} catch (IOException e) {
}
}
webViewInfo.loadDataWithBaseURL(null, result.toString(), "text/html", "UTF-8", null);
}

private void getResponseApache(HttpUriRequest request) {
HttpResponse response = null;
try {
response = client.execute(request);//重定向 RedirectStrategy execute while (!done)
} catch (ClientProtocolException e) {
textViewInfo.setText(e.getMessage());
} catch (IOException e) {
textViewInfo.setText(e.getMessage());
}

if (response == null) {
return;
}

if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
textViewInfo.setText("error response" + response.getStatusLine().toString());
return;
}

String result = null;
try {
result = EntityUtils.toString(response.getEntity(),"UTF-8");
} catch (Exception e) {
textViewInfo.setText("error response" + response.getStatusLine().toString());
return;
}
webViewInfo.loadDataWithBaseURL(null, result, "text/html", "UTF-8", null);
}
}


看看运行效果:

主界面:



点击 使用java登录iteye,弹出登录对话框:



输入javaeye的账号和密码,点击登录(有点慢,耐心等待),结果如下:



登录成功了,点击 iteye收件箱(相当于在浏览器里点击收件箱),验证是同一session



成功,代码没有问题。

使用Apache的方式结果一样,我就不截图了。

做这个例子,我是想了解http协议,httpclient内部实现原理。写的过程中参照如下:

seesion问题:http://hi.baidu.com/%CE%A4%D7%D4%C9%FD/blog/item/e2ce0004f52f2c61030881fa.html

http://helin.iteye.com/blog/257115

302重定向:/article/11361226.html

http 417 :http://blog.yes2.me/archives/915

webview乱码:/article/3874105.html

接下来分析一下代码:

先分析java部分,代码和我上篇博客node.js+android http请求响应基本很像,关键的不同

1.解决session的代码:

private String cookie;

if(cookie != null) {//session_id
urlConnection.setRequestProperty("Cookie", cookie);
}

cookie = urlConnection.getHeaderField("Set-Cookie");//session_id


共享cookie,获取响应前查看是否有cookie,如果有则放在请求头上,获取响应后,拿到cookie存下来。

2.解决重定向的代码:

if(responseCode == 301 || responseCode == 302 || responseCode == 307) {//重定向
String location = urlConnection.getHeaderField("location");
URL url = null;
try {
url = new URL(location);
} catch (MalformedURLException e) {
}

HttpURLConnection urlConnectionRedirect = null;
try {
urlConnectionRedirect = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
textViewInfo.setText(e.getMessage());
return;
}

getResponseJava(urlConnectionRedirect);
return;
}
查看响应代码是否需要重定向,如果是读出响应头上的location,发出get请求,递归调用。

再来分析一下httpclient部分:

1.解决407 error

HttpParams httpParams = client.getParams();
httpParams.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);


2.解决session

private DefaultHttpClient client;


共用一个client就可以了,cookie存在这client.getCookieStore().getCookies(), 和我们使用一个浏览器,多个标签页共享session原理一样。

3.解决重定向

没有附加任何代码,httpclient内部已经实现,源码主要部分如下:

class AbstractHttpClient
public final HttpResponse execute(HttpUriRequest request)
throws IOException, ClientProtocolException {

return execute(request, (HttpContext) null);
}
public final HttpResponse execute(HttpHost target, HttpRequest request,
HttpContext context)

RequestDirector director = null;
director = createClientRequestDirector    return new DefaultRequestDirector
return director.execute(target, request, execContext);

class DefaultRequestDirector
public HttpResponse execute(HttpHost target, HttpRequest request,
HttpContext context)
while (!done) {
RoutedRequest followup = handleResponse(roureq, response, context);
if (followup == null) {
done = true;
} else {

protected RoutedRequest handleResponse(RoutedRequest roureq,
HttpResponse response,
HttpContext context)
if (HttpClientParams.isRedirecting(params) &&
this.redirectStrategy.isRedirected(request, response, context)) {

class DefaultRedirectStrategy
public boolean isRedirected(
final HttpRequest request,
final HttpResponse response,
final HttpContext context)

int statusCode = response.getStatusLine().getStatusCode();
String method = request.getRequestLine().getMethod();
Header locationHeader = response.getFirstHeader("location");
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
return (method.equalsIgnoreCase(HttpGet.METHOD_NAME)
|| method.equalsIgnoreCase(HttpHead.METHOD_NAME)) && locationHeader != null;
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_TEMPORARY_REDIRECT:
return method.equalsIgnoreCase(HttpGet.METHOD_NAME)
|| method.equalsIgnoreCase(HttpHead.METHOD_NAME);
case HttpStatus.SC_SEE_OTHER:
return true;
default:
return false;
} //end of switch


处理方法基本和我的一样,除了对象封装意外,它使用的条件循环 while (!done) ,我使用的是条件递归。

ps:使用windows7以后,根据内容找文件很蛋疼,推荐大家使用 UltraFileSearch 官网 http://www.ultrafilesearch.com/,不是广告,只是用了这么多搜索替代工具以后,觉得最好的一个,和大家分享一下

敲了半天怪累的,就说到这了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐