封装MIDP 1.0 HttpConnection用于商业应用[javaME]
2005-12-01 18:18
573 查看
另外,还有一篇必读的文章《Debugging MIDP HTTP Requests,http://developers.sun.com/techtopics/mobility/midp/articles/httpdebug/》,也给出了一份源代码,http://developers.sun.com/techtopics/mobility/midp/articles/httpdebug/src/httpwrapper.zip,算是另外一种封装实现了。
一个来自日本的MIDP 1.0 HttpConnection类的robust封装
作者:zhengyun_ustc、cleverpig
一、“NetConnection”简介:
转述Matrix上zhengyun_ustc所述:“你的HttpConnection是否封装的足够健壮呢?遇到各种情况,你是否有信心应对呢?譬如说,你要请求的Response包实在太大,以至于运营商给你掐了告诉你说超时;譬如说你是不是总要自己写一个线程来专门作http连接?譬如说有一些移动运营商设置了caching proxy servers,妨碍了你的测试。”
为了解决这个问题,一位日本程序员“JAY-F”针对MIDP1.0提供了一种robust的“NetConnection”封装。这个HttpConnnection类负责管理连接并易于使用。
二、“NetConnection”特性:
1. 跨过Proxy-server阻碍:
一些移动网络放置了代理服务器用来提高访问速度,但是它的cache也成为了开发人员测试/调试程序的一大障碍。“NetConnection”类使用一个简单的http request属性将server上的代理功能关闭掉。
2. 使用线程分离的连接模式:
本类可以使用单线程、多线程两种模式运行,只要设置一个简单的标志即可。
3. 支持Http request range:
由于服务商在其网络上可能存在一些针对回应数据最大长度的限制,所以“NetConnection”类提供了构造request URL的功能使回应数据分为多个数据包。从而去除了前面的限制。
三、netConnection是如何实现的?
1。netConnection类结构分析:
此类实现了Runnable接口,其运行模式支持多线程模式:当前只能由一个线程使用资源,其它线程wait。
此类使用了一些静态成员变量:
//当前只能由一个线程使用singleton。 private static NetConnection singleton = new NetConnection(); private static HttpConnection httpConn; private static String url; private static String method; private static byte[] data; private static String contentType; private static long lowRange; private static long highRange; private static boolean disableProxy; private static boolean detached; private static byte[] response;
类方法:
//线程run方法 public void run() //当前运行的线程执行完毕后,通报给其它的由于等待资源而wait状态的线程 private synchronized void forceNotify() //当资源正在被其它线程使用时,当前线程进入wait状态 private synchronized void forceWait() //关闭http连接 private static void severConnection()
由于使用了这些static成员变量,所以一些操作方法需要同步(synchronized)。
2。netConnection核心代码解析:
netConnection类的实现思想很简单,就是设置一些request属性和对于GET方法构造一个特殊的URL。更重要的是其作者对http协议的深入理解、严谨的代码风格值得吾辈学习、研究。这也是本人分析其核心代码的一大原因。
/** * 实现了连接逻辑。 * 调用者可以在分离的线程中使用netConnection类的静态连接。 * @throws IllegalStateException 如果此方法直接其它类调用则抛出该异常 */ public void run() { if (url == null) { throw new IllegalStateException("Cannot invoke this method!"); } DataOutputStream dos = null; DataInputStream dis = null; StringBuffer buffer = null; try { int permissions = 0; //根据method值,设置Connector的权限(READ/READ_WRITE) if (HttpConnection.GET.equals(method)) { permissions = Connector.READ; } else if (HttpConnection.POST.equals(method)) { permissions = Connector.READ_WRITE; } //如果关闭server代理功能,则构造noProxyUrl。 //原理:使用timestamp作为该URL中no-proxy参数值, // 致使server视其为client发来的新请求。 if (disableProxy) { boolean hasQueryParams = false; char[] ca = url.toCharArray(); //判断原URL中是否含有参数 for (int loop = 0; loop < url.length(); loop++) { if (ca[loop] == '?') { hasQueryParams = true; break; } } //由于需要多次字符串拼接,所以使用可提供效率的StringBuffer类 StringBuffer noProxyUrl = new StringBuffer(); //将原URL内容复制到noProxyUrl noProxyUrl.append(url); //如果原URL中含有参数, // 则需要在noProxyUrl中增加"&", // 否则直接在noProxyUrl中增加"?", // 这样做为了后面增加no-proxy参数做准备。 if (hasQueryParams) { noProxyUrl.append("&"); } else { noProxyUrl.append("?"); } //增加no-proxy参数 noProxyUrl.append("no-proxy="); noProxyUrl.append(System.currentTimeMillis()); // timestamp //将构造好的noProxyUrl复制到原URL url = noProxyUrl.toString(); } // 打开Http 连接 httpConn = (HttpConnection) Connector.open(url, permissions, true); //设置request方法 httpConn.setRequestMethod(method); //如果request权限为READ(即request方法为GET), //则需要设置http request属性的Range。 //原理:设置http request属性的Range后的, // server接收到该request后将把response数据分成小部分发回。 // 从而避免了部分运营商对http response size的限制。 if (permissions == Connector.READ) { if (lowRange > -1 && lowRange < highRange) { StringBuffer range = new StringBuffer(); range.append("bytes="); range.append(lowRange); range.append("-"); range.append(highRange); httpConn.setRequestProperty("Range", range.toString()); } //否则,request权限为READ_WRITE(即request方法为POST), //那么设置request的Content-Type属性。 } else if (permissions == Connector.READ_WRITE) { // POST request httpConn.setRequestProperty("Content-Type", contentType); dos = httpConn.openDataOutputStream(); dos.write(data); } } catch (Exception e) { exceptionPipe = e; //如果程序运行在多线程模式,则在异常发生后需要唤醒其它睡眠的线程继续run if (detached) { forceNotify(); } return; } finally { try { try { if (dos != null) { // 关闭dos dos.close(); } } catch (Exception e) { // 如果程序运行在多线程模式,则在异常发生后需要唤醒其它睡眠的线程继续run if (exceptionPipe == null) { exceptionPipe = e; if (detached) { forceNotify(); } return; } } finally { dos = null; } // 读取http连接的回应代码 int responseCode = httpConn.getResponseCode(); //当request方法为GET,并设置了request range时,接收到的回应代码为HTTP_PARTIAL //当request方法为POST,接收到的回应代码为HTTP_OK //如果上述两种回应代码均没有收到,则表明连接失败或者出问题 if (responseCode != HttpConnection.HTTP_OK && responseCode != HttpConnection.HTTP_PARTIAL) { if (exceptionPipe == null) { StringBuffer errorCode = new StringBuffer(); errorCode.append("Response code from server: "); errorCode.append(responseCode); errorCode.append("\nMessage: ["); errorCode.append(httpConn.getResponseMessage()); errorCode.append("]"); exceptionPipe = new IOException(errorCode.toString()); if (detached) { forceNotify(); } return; } } //如果收到了上述的两种回应代码之一,则可以继续读取server的response数据 dis = httpConn.openDataInputStream(); //循环读取repsonse数据 int ch; buffer = new StringBuffer(); while ((ch = dis.read()) != -1) { buffer.append((char) ch); } //将response数据进行必要的编码转换 response = buffer.toString().getBytes("ISO8859_1"); //接收到回应后,表明整个http会话过程结束,线程将结束。 //如果程序运行在多线程模式,则此时需要唤醒其它睡眠的线程继续run if (detached) { forceNotify(); } return; } catch (Exception e) { if (exceptionPipe == null) { exceptionPipe = e; if (detached) { forceNotify(); } return; } } finally { try { if (dis != null) { // 关闭dis dis.close(); } } catch (Exception e) { // 若关闭dis时发生异常,则进行异常处理 if (exceptionPipe == null) { exceptionPipe = e; if (detached) { forceNotify(); } return; } } finally { dis = null; } try { if (httpConn != null) { //关闭http连接 httpConn.close(); httpConn = null; } } catch (Exception e) { if (exceptionPipe == null) { exceptionPipe = e; if (detached) { forceNotify(); } return; } } } } }
五、参考资料:
联系netConnection作者:JAY-F
源代码下载
HTTP/1.1定义
不知道大家会更喜欢哪一种封装呢?
是HttpConnectionWrapper吗?
他的调用方法:
Wait w = (Wait) display.getCurrent();
HttpConnection conn = null;
InputStream in = null;
try {
conn = new HttpConnectionWrapper( (HttpConnection) Connector.open( url ) );
conn.setRequestProperty( "User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0" );
conn.setRequestProperty( "Connection", "close" );
conn.setRequestProperty( "Send-HTTP-Log-To", "ericgiguere@ericgiguere.com" );
int rc = conn.getResponseCode();
w.update( "Response code " + rc );
in = conn.openInputStream();
for( int i = 0; i < 100; ++i ){
if( in.read() == -1 ) break;
}
封装类示意:
/**
* A wrapper for the HttpConnection interface that logs method
* calls and state transitions. Wrap a connection immediately
* after obtaining it from Connector.open. Information is logged
* according to the log level set the "httpwrapper" logger.
*/
public class HttpConnectionWrapper implements HttpConnection {
还是NetConnection?
他的调用方法:
NetConnection.connect("http://www.molon.com.cn/",data,HttpConnection.GET,...);
封装类示意:
/**
* This class provides robust network connectivity and exception handling
* over an unreliable MIDP HttpConnection.
*
* In addition the caller may perform a combination of any of the below
* functions.
*
* - Proxy-server thwarting
* - HTTP range requests
* - Thread-separated connections
*
* @author Jason Fuerstenberg (http://www.jay-f.jp)
* @version 2004/03/15
*/
public final class NetConnection implements Runnable {
相关文章推荐
- 来自日本程序员的MIDP 1.0 HttpConnection类的robust封装
- 来自日本程序员的MIDP 1.0 HttpConnection类的robust封装
- 【封装】异步HttpURLConnection网络访问
- android网络应用(二)——HttpURLConnection和HttpClient
- 封装的Http请求(HttpURLConnection和okHttp)
- Android--HttpUrlConnection+JSON应用实例 (2)
- 网络请求封装类lmxHttpUrlConnection
- Android HttpURLConnection应用技巧分享
- Android之用HttpURLConnection参数以XML形式封装的部分关键代码
- 那些年我们踩到过的坑(二):3.1 版 MultiThreadedHttpConnectionManager 未releaseConnection导致应用服务器宕机
- Android代码(Handler的运用),HttpURLConnection的应用,将url图片地址转换成图片。
- 封装 HttpURLConnection
- HttpClient3.1 未releaseConnection导致应用服务器宕机
- HttpURLConnection 单独封装网络请求工具类
- URL,URLConnection,HttpURLConnection的简单应用
- HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)
- HttpURLConnection应用
- HttpURLConnection获得网络数据(Gson应用)
- NetSNS_Ver1.0源码学习版 仅供研究和学习,切勿用于商业用途
- 配置了拦截器的应用执行HttpURLConnection之connect方法遇到的问题