之前在网上看过好多人用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重定向:http://blog.csdn.net/hegch/article/details/1891146
http 417 :http://blog.yes2.me/archives/915
webview乱码:http://hongyang321.iteye.com/blog/1021564
接下来分析一下代码:
先分析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;
- }
再来分析一下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/,不是广告,只是用了这么多搜索替代工具以后,觉得最好的一个,和大家分享一下
敲了半天怪累的,就说到这了。