Android利用Cookie实现码源登录效果二

来源:互联网 发布:mac 命令行安装wget 编辑:程序博客网 时间:2024/06/16 22:58

功能实现

  • 使用HttpClient进行post请求
    在进行post请求的时候,我们先看看网页版登录是如何发送数据的。

    打开登录页面,点击键盘上的F12,在Sources中找到login,找到发送ajax请求进行登录的部分,加入断点:

    点击登录,然后在Network中看到有个发送到http://www.codefrom.com/login/ajax 的网络请求,点开它,我们看看Header里面有什么数据:

    可以看到,有三部分数据:Request URL 、 Request Header 和 Form Data,他们的含义我想大家应该都很清楚。那么我们就尝试在LoginActivity中模拟一下这个操作。

    首先,我们写一个方法,封装我们的登录请求:

    public String sendPost(String url, String username, String password) {    // 根据url获得HttpPost对象    HttpPost httpRequest = new HttpPost(url);    // 取得默认的HttpClient    DefaultHttpClient httpclient = new DefaultHttpClient();    String strResult = null;    // NameValuePair实现请求参数的封装    List<NameValuePair> params = new ArrayList<NameValuePair>();    params.add(new BasicNameValuePair("_tk", "codefrom"));    params.add(new BasicNameValuePair("name", username));    params.add(new BasicNameValuePair("pass", password));    httpRequest.addHeader("Accept", "application/json, text/javascript, */*; q=0.01");    httpRequest.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");    httpRequest.addHeader("Origin", "http://www.codefrom.com");    httpRequest.addHeader("Referer", "http://www.codefrom.com/login");    httpRequest.addHeader("X-Requested-With", "XMLHttpRequest");    try {        // 添加请求参数到请求对象        httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));        // 获得响应对象        HttpResponse httpResponse = httpclient.execute(httpRequest);        // 判断是否请求成功        if (httpResponse.getStatusLine().getStatusCode() == 200) {            // 获得响应返回Json格式数据            strResult = EntityUtils.toString(httpResponse.getEntity());            return strResult;        } else {            strResult = "错误响应:" + httpResponse.getStatusLine().toString();        }    } catch (ClientProtocolException e) {        strResult = "错误响应:" + e.getMessage().toString();        e.printStackTrace();        return strResult;    } catch (IOException e) {        strResult = "错误响应:" + e.getMessage().toString();        e.printStackTrace();        return strResult;    } catch (Exception e) {        strResult = "错误响应:" + e.getMessage().toString();        e.printStackTrace();        return strResult;    }    return strResult;}

    (注:当前版本网络请求只能异步操作)
    然后,在UserLoginTaskdoInBackground中,当睡眠结束后,我们对登录方法进行调用:

    String res = sendPost("http://www.codefrom.com/login/ajax", mEmail, mPassword);Log.d("CodeFromLogin", res);

    我们运行项目,看看日志中打印:

    没错,将Unicode转成中文之后,得到“操作成功”的返回信息!
    需要注意一点,一开始,我没有添加httpRequest.addHeader这部分的内容,得到的结果如下:

    感兴趣的同学可以尝试一下,服务器返回提示我们操作失败,缺少ajax头部信息!

  • 保存来自服务器的Cookie
    能够成功发送数据给服务器,并且服务器能响应结果,那么,我们能否获取更多内容呢?当然可以!HttpClient提供了下面的方法供我们获取Cookie:

    // 取得CookieCookieStore mCookieStore = httpclient.getCookieStore();List<Cookie> cookies = mCookieStore.getCookies();

    那么,Android又是如何对Cookie进行管理的呢?

    // 设置cookiepublic static void synCookies(Context context, String url) {      CookieSyncManager.createInstance(context);      CookieManager cookieManager = CookieManager.getInstance();      cookieManager.setCookie(url, "uid=1243432");                  CookieSyncManager.getInstance().sync();  }// 清除cookieprivate void removeCookie(Context context) {    CookieSyncManager.createInstance(context);      CookieManager cookieManager = CookieManager.getInstance();     cookieManager.removeAllCookie();    CookieSyncManager.getInstance().sync();  }

    接下来,我们就可以对sendPost方法进行一些改造了:

    public CookieManager cookieManager = null;public static String cookies;public String sendPost(String url, String username, String password) {  CookieSyncManager.createInstance(LoginActivity.this);  // 每次登录操作的时候先清除cookie  removeAllCookie();  // 根据url获得HttpPost对象  HttpPost httpRequest = new HttpPost(url);  // 取得默认的HttpClient  DefaultHttpClient httpclient = new DefaultHttpClient();  String strResult = null;  // NameValuePair实现请求参数的封装  List<NameValuePair> params = new ArrayList<NameValuePair>();  params.add(new BasicNameValuePair("_tk", "codefrom"));  params.add(new BasicNameValuePair("name", username));  params.add(new BasicNameValuePair("pass", password));  httpRequest.addHeader("Accept", "application/json, text/javascript, */*; q=0.01");  httpRequest.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");  httpRequest.addHeader("Origin", "http://www.codefrom.com");  httpRequest.addHeader("Referer", "http://www.codefrom.com/login");  httpRequest.addHeader("X-Requested-With", "XMLHttpRequest");  try {      // 添加请求参数到请求对象      httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));      // 获得响应对象      HttpResponse httpResponse = httpclient.execute(httpRequest);      // 判断是否请求成功      if (httpResponse.getStatusLine().getStatusCode() == 200) {          // 获得响应返回Json格式数据          strResult = EntityUtils.toString(httpResponse.getEntity());          // 取得Cookie          CookieStore mCookieStore = httpclient.getCookieStore();          List<Cookie> cookies = mCookieStore.getCookies();          if (cookies.isEmpty()) {              System.out.println("Cookies为空");          } else {              for (int i = 0; i < cookies.size(); i++) {                  // 保存cookie                  Cookie cookie = cookies.get(i);                  Log.d("Cookie", cookies.get(i).getName() + "=" + cookies.get(i).getValue());                  cookieManager = CookieManager.getInstance();                  String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();                  cookieManager.setCookie("http://www.codefrom.com/", cookieString);              }          }          return strResult;      } else {          strResult = "错误响应:" + httpResponse.getStatusLine().toString();      }  } catch (ClientProtocolException e) {      strResult = "错误响应:" + e.getMessage().toString();      e.printStackTrace();      return strResult;  } catch (IOException e) {      strResult = "错误响应:" + e.getMessage().toString();      e.printStackTrace();      return strResult;  } catch (Exception e) {      strResult = "错误响应:" + e.getMessage().toString();      e.printStackTrace();      return strResult;  }  return strResult;}private void removeAllCookie() {  cookieManager = CookieManager.getInstance();  cookieManager.removeAllCookie();  CookieSyncManager.getInstance().sync();  }

    运行改造之后的代码,我们先进行登录,然后点击按钮打开码源首页,可以看到,首页导航是可以看到登录信息的!

  • 使用本地广播更新界面
    完成登录之后,我们需要修改主界面的控件文字,比如我们想显示用户名等等。理论上来讲,使用startActivity将数据通过Intent从登录界面传递给主界面的方法是可行的。但是,我们需要考虑在实际中,如果多个地方校验到用户没有登录,都需要弹出登录界面,然后登录完了之后,我们需要返回的界面不一定都是主界面(如果PM要求返回主界面,当我没说),那我们该怎么办呢?
    这时,我们可以通过本地广播来实现:在主界面(或者其他需要得到登录信息的界面),动态注册一个本地广播,通过广播获取到的Intent来进行数据分析,部分代码如下:

    localBroadcastManager = LocalBroadcastManager.getInstance(MainActivity.this);IntentFilter intentFilter = new IntentFilter();intentFilter.addAction("com.codefrom.broadcastreceiver.LOGIN_BROADCAST");//建议把它写一个公共的变量,这里方便阅读就不写了。loginBroadcastReceiver = new BroadcastReceiver() {    @Override    public void onReceive(Context context, Intent intent) {        Bundle bundle = intent.getExtras();        boolean result = bundle.getBoolean("result");        String user = bundle.getString("username");        if (result) {            username.setText(user);            Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();            loginbtn.setText("退出登录");            isLogin = true;        } else {            Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show();            username.setText("未登录");            loginbtn.setText("登录");            isLogin = false;        }    }};localBroadcastManager.registerReceiver(loginBroadcastReceiver, intentFilter);

    同时,在登录界面,登录成功之后,我们可以发送一个广播告知其他界面登录结果,由于登录在子线程中进行,我们就需要借助Handler进行广播发送:

    Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {    LoginInfo loginInfo = (LoginInfo) msg.obj;    Toast.makeText(LoginActivity.this, loginInfo.getStatus() + " - " + loginInfo.getMsg() + " - " + Uri.decode(loginInfo.getMsg()) , Toast.LENGTH_SHORT).show();    if("1".equals(loginInfo.getStatus())) {        Intent intent = new Intent("com.codefrom.broadcastreceiver.LOGIN_BROADCAST");        Bundle bundle = new Bundle();        bundle.putBoolean("result", true);        bundle.putString("username", "单车武士");        intent.putExtras(bundle);        localBroadcastManager.sendBroadcast(intent);    }};};

    其实,如果观察LoginActivity,在成功以后,它做的操作是调用Activity的finish(),也就是直接关闭登录界面了,我猜系统应该也是不推荐直接使用startActivity进行显示跳转的。
    由于服务器并没有给我们返回更多用户的信息,我们先返回一个写死的username过去……当然,在网页中是根据cookie来获取用户信息的,这方面的东西在Android上面的实现我们今后再探讨。

以上就是我们实现的模拟登录码源效果,如果有什么不对的地方或者更好的建议,欢迎回复交流。

0 0