网络错误处理与重试机制

在开发网络应用时,经常遇到各种网络错误,如数据包丢失、连接超时、需要处理cookies等。这些错误在开发初期往往被忽视,但它们对于移动网络用户来说尤为重要。本文旨在介绍一种框架,它不仅能够处理这些常见的网络错误,还能简化重试通信的流程。

快速开始

要快速开始使用这个框架,可以下载示例的Eclipse项目代码。请注意,仍然需要下载并链接WorxForUs框架文件,具体步骤如下:

功能特点

这个框架提供了以下功能:

访问网络(无需认证)

首先,需要从GitHub页面下载WorxForUs框架,或者克隆到本地。然后将项目导入到Eclipse或Android Studio中。接下来,检查网络是否连接(如果用户开启了飞行模式,不应该尝试下载任何东西)。

// NetResult是一个用于存储结果的对象 NetResult netResult = null; String url = "http://www.google.com/"; // 加载要发布的值 List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("q", "bears")); String serverResponse = ""; // 如果当前网络未连接,则不尝试通信 if (NetHandler.isNetworkConnected(con)) { netResult = NetHandler.handlePostWithRetry(url, params, NetHandler.NETWORK_DEFAULT_RETRY_ATTEMPTS); // 获取服务器响应作为字符串 serverResponse = Utils.removeUTF8BOM(EntityUtils.toString(net_result.net_response_entity, Utils.CHARSET)); // 通知HTTP客户端所有数据已读取 netResult.closeNetResult(); }

NetResult对象包含了从web服务器解码响应所需的所有信息。如果netResult.net_response_entity不为null,那么这就是服务器的响应。将该值发送到处理路由。

NetResult对象的属性如下:

  • net_success - 当成功联系到服务器时为true(但这并不表示请求是有效的)
  • net_error - 包含与连接相关的错误消息或异常
  • net_error_type - 包含发生的错误类型名称(例如HttpResponseException、SocketTimeoutException、SocketException或IOException)
  • net_response_entity - 这是服务器的实际响应。一个常见的用途是运行: String consume_str = Utils.removeUTF8BOM(EntityUtils.toString(net_result.net_response_entity, Utils.CHARSET)); 或者如果想捕获JSON数据: NetResult.handleGenericJsonResponseHelper(net_result, this.getClass().getName()); 注意:类名仅用于日志记录。现在net_result.object将包含JSON对象解析。

从netResult.net_response_entity读取数据后,需要调用netResult.closeNetResult()。这个函数最终会调用HttpEntity.consumeContent(),释放与该对象相关的任何资源。

访问网络(需要认证)

一旦为特定的web服务器配置了认证助手,调用网络认证就变得简单了。

// 加载认证数据 if (!AuthNetHandler.isAuthenticationSet()) { // 传递上下文允许系统更新首选项 AuthNetHandler.setAuthentication(host, new MyAuthenticationHelper(con)); NetAuthentication.loadUsernamePassword(username, password); } // 如果网络准备好了,那么继续 // 检查用户是否禁用了网络 if (NetHandler.isNetworkConnected(context)) { // 如果用户有凭据 - 上传然后下载,这样数据就不会丢失 if (NetAuthentication.isReadyForLogin()) { netResult = AuthNetHandler.handleAuthPostWithRetry(url, params, num_retries); // ...在这里处理netResult响应 netResult.closeNetResult(); } else { Log.e(this.getClass().getName(), "Did not attempt to login, no authentication info"); } }

当有认证请求时,在调用AuthNetHandler.handleAuthPostWithRetry(...)之前,需要实现一个NetAuthenticationHelper类。这将告诉框架如何登录,哪些消息是错误消息,以及如何验证登录。这可能看起来有很多额外的代码,但请尽量坚持。将所有认证代码放在一个地方可以非常有帮助。

public class MyAuthHelper implements NetAuthenticationHelper { @Override public String getLoginURL(String host) { return "https://myweb/remote_login_address.php"; } // getLoginURL简单地是期望应用程序在发送登录参数时连接的位置。在这里放入需要的URL。 @Override public void markAsLoginFailure(NetResult result) { result.object = new String("Login Error"); } // 或者,在情况下,使用JSON对象: @Override public void markAsLoginFailure(NetResult result) { try { result.object = new JSONObjectWrapper("Jsonstring"); } catch (JSONExceptionWrapper e) { throw new RuntimeException("Could not parse default login failed JSON string."); } } // 在这里放入web服务器在用户登录失败时的响应。这个部分强制一个结果被模拟为登录失败在result.object变量中。假设已经识别出一个失败的登录,这个输出会通过validateLoginResponse(...)发送,在那里失败的登录会被识别。 @Override public void markAsLoginSuccessFromCache(NetResult result) { result.object = new String("Login Successful"); } // 在这里放入web服务器在用户成功登录时可能的响应。这个部分强制一个结果被模拟为登录成功在result.object变量中。 @Override public String getLoginErrorMessage() { return "Could not login user"; } // 这里,放入希望被传递为netResult.net_error的错误消息,当用户不能登录时。 @Override public int validateLoginResponse(NetResult netResult) { // 返回NetAuthentication.NO_ERRORS, NETWORK_ERROR, 或 SERVER_ERROR // 检查登录服务器结果从netResult.object // 以确定登录是否成功 if (netResult.net_success) { String response = netResult.object; if (response.contains("not logged in indication")) { return NetAuthentication.NOT_LOGGED_IN; } else if (response.contains("login error indication")) { return NetAuthentication.LOGIN_FAILURE; } else if (response.contains("cant parse data indication")) { return NetAuthentication.SERVER_ERROR; } } else { return NetAuthentication.NETWORK_ERROR; } return NetAuthentication.NO_ERRORS; } // validateLoginResponse(...)执行大部分登录检查,它确定用户是否未登录,是否有登录错误(例如,错误的密码),服务器错误或网络错误。根据从服务器期望的,将发送一个响应NetAuthentication.NO_ERRORS, NETWORK_ERROR, 或 SERVER_ERROR。 @Override public int peekForNotLoggedInError(NetResult netResult) { // ...检查netResult.object在登录页面之外的页面上登录失败。 } // 与前面的函数类似,peekForNotLoggedInError(...)检查登录错误,但在不是登录页面的页面上。考虑一个例子,已经登录了,但然后检查一个不同的页面来下载一些其他数据。如果用户会话突然注销,将得到一个错误,可能看起来与在登录页面上得到的错误不同。所以,特定的逻辑对于意外的登录失败在这里。 @Override public NetResult handleUsernameLogin(String host, String username, String password) { List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("uname_field", "username")); params.add(new BasicNameValuePair("pword_field", "password")); // ... NetResult netResult = NetHandler.handlePostWithRetry(this.getLoginURL(host), params, NetHandler.NETWORK_DEFAULT_RETRY_ATTEMPTS); // 保存结果并关闭网络流 consume_str = Utils.removeUTF8BOM(EntityUtils.toString(result.net_response_entity, Utils.CHARSET)); netResult.object = consume_str; netResult.closeNetResult(); return netResult; } // handleUsernameLogin(...)函数提供了实际字段和逻辑,需要将请求发送到web服务器。简单地填写特定字段登录。 // 如果有一个使用令牌的不同请求,可以使用handleTokenLogin(...)函数。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485