Chinaunix首页 | 论坛 | 博客
  • 博客访问: 477513
  • 博文数量: 155
  • 博客积分: 2954
  • 博客等级: 少校
  • 技术积分: 1000
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-12 22:00
文章分类

全部博文(155)

文章存档

2014年(2)

2013年(5)

2012年(10)

2011年(33)

2010年(105)

我的朋友

分类:

2010-05-17 17:03:11

这个问题是在我升级J2ME版XHTML浏览器的时候被引入的,我尝试了很多方法、发了很多帖子、问了很多人都没有找到可行的解决方案。最后我在PC上通用OTA连接方式使用WireShark拦截数据包才解决了问题,接下来我和大家分享一下解决问题的过程。

  所涉及的知识点:

  1、如何使用J2ME连接cmwap代理

  2、基于安全套接字的HTTPS

  尝试方法一:

  新建一个Midlet应用程序,在StartApp方法中加入如下代码:

 


      1 HttpConnection conn = null; 
  2 InputStream is = null; 
  3 try { 
  4 // url: 
  5 conn = (HttpConnection) Connector.open("", Connector.READ, true); 
  6   = "ebs.95559.com.cn"; 
  7 conn.setRequestProperty("x--host", host); 
  8 conn.setRequestMethod(HttpConnection.GET); 
  9 
  10   = conn.getResponseCode(); 
  11 .out.println("Response Code: " + code); 
  12 
  13 is = conn.openDataInputStream(); 
  14 
  15 System.out.println("Response Stream:"); 
  16 byte[] buf = new byte[128]; 
  17 while (true) { 
  18 int availSize = is.read(buf, 0, buf.length); 
  19 if (availSize == -1) { 
  20 break; 
  21 } 
  22 System.out.println(new String(buf, 0, availSize)); 
  23 } 
  24 } catch (Exception ex) { 
  25 ex.printStackTrace(); 
  26 } finally { 
  27 if (is != null) { 
  28 try { 
  29 is.close(); 
  30 } catch (IOException ex) { 
  31 ex.printStackTrace(); 
  32 } 
  33 } 
  34 
  35 if (conn != null) { 
  36 try { 
  37 conn.close(); 
  38 } catch (IOException ex) { 
  39 ex.printStackTrace(); 
  40 } 
  41 } 
   } 
  43

 

  此代码的作用是:使用cmwap代理,请求我们制定的页面,并在控制台中输出返回的状态码及内容。很显然,这是一种普通的cmwap连接方式,并没有考虑https因素的加入,输出的结果也在意料之内:

 


Response Code: 502 
Response Stream: 
 
 
<> 

 to host failed. Check your settings and try again. If the pro 
blem persists contact your .

 

 

 

原因分析:我们要请求的是安全HTTP,端口443,而在我们的代码中并没有体现出我们要连接HTTPS的意图,我们只是告诉了cmwap代理我们要连接地址“ebs.95559.com.cn/corporbank/es_logon.jsp”,而并没有告诉cmwap代理我们所要访问的地址是基于HTTPS的,所以cmwap代理会按照地址“”去连接,恰好这个地址是不支持HTTP:80的,cmwap代理返回了网关错误。

 

  尝试方法二:

  针对以上设想,我们将代码修改一下,想方设法让cmwap代理知道我们要访问的目标地址属于HTTPS:443。

  修改程序的第6行,使其变成:

 


String host = "ebs.95559.com.cn:443";

 

  运行,控制台还是输出了以下错误:

 


Response Code: 500 
Response Stream: 
 
 
 

Your request for a service could not be fulfilled. Please try again or c 
ontact your operator if the problem persists. 

 

原因分析:不详。

 

  尝试方法三:

  以上两种方法都行不通,有没有可能cmwap代理服务器开通了SSL端口,来让应用程序通过此端口来访问HTTPS呢?

  将代码第5行修改如下:

 


conn = (HttpConnection) Connector.open("", Connector.READ, true);

 

  模拟器长时间没有响应。

  原因分析:一般手机自带的浏览器都支持访问HTTPS,而手机设置的cmwap代理地址都是10.0.0.172:80。所以可以肯定的是手机是可以通过10.0.0.172:80这个代理访问HTTPS而并不是10.0.0.172:443。上网查了资料,证明移动针对cmwap代理只开通了80 端口,而并没有开通443端口。

  尝试方法四(成功):

  经过了以上三次失败,我不得不好好静下心来想想解决方法。我想到了使用OTA的方式,让PC连接到GPRS上进行调试。首先使用数据线连接电脑和手机,将电脑的本地连接禁用,把手机当猫用,创建基于手机拨号的网络连接,输入号码“*99#”,拨号,连接。给浏览器设置好代理 10.0.0.172:80后,能够正常浏览HTTPS地址。我忽然想到,既然HttpConnection不能够正常通过cmwap连接HTTPS,那我使用Socket模拟HTTP请求能成功吗?带着这个疑问,我开始进行准备:

  必备工具:

  Wireshark或HttpWatch或Openware Simulator

  最开始我是使用Firefox+Wireshark拦截80端口的包的,但是浏览器向服务器发出SSL Hello后传输的内容都会被加密,Wireshark所看到的都是密文,相当的不方便。如图:

  image

  后来我发现,Openware Simulator提供浏览器,且本身就提供了类似于Wireshark的功能,而且可以截获到HTTP层所传输的内容,能够很清楚的看见客户端与服务器端来往的过程。所以,我们以Openware Simulator的截图作为说明。Openware Simulator下载地址:这里(免费,需要邮件注册)

  还可以使用HttpWatch 6.0,新版HttpWatch已经可以作为Firefox的扩展嵌入。不过这个要收大洋,还是Openware Simulator来得直接一些。

  实现方法:

  打开Openwave V7 Simulator,在模拟器地址栏输入网址,截图如下:

  image

  通过右边的控制台输出窗口,我们可以很清楚的看到Openware Simulator通过向cmwap代理所发出的请求格式。并且,通过Socket连接,是不需要添加“x-onlinhost”请求头的。

  既然HttpConnection行不通,我们自己就使用Socket实现Http连接,向cmwap代理发出请求。

  此处要先说明以下两点:

  1、J2ME中的SocketConnection是MIDP 2.0的可选包,并不是每个手机都提供Socket的支持;

  2、我们必须使用Socket连接cmwap代理10.0.0.172:80,而MIDP 2.0对Socket访问80端口加了限制,在真机上使用必须得使用证书签署生成的JAD,否则会抛出安全异常。

  在此我不按照Openware Simulator控制台中显示的连接顺序(先Connect后Get)进行连接,使用Openware Simulator只是证明我想法的可行性,我将直接使用Get+完整URL的方式进行代码的编写。

   这个问题是在我升级J2ME版XHTML浏览器的时候被引入的,我尝试了很多方法、发了很多帖子、问了很多人都没有找到可行的解决方案。最后我在PC上通用OTA连接方式使用WireShark拦截数据包才解决了问题,接下来我和大家分享一下解决问题的过程。

  新建一个Midp应用程序,在startApp中加入以下代码:

 


      1 SocketConnection conn = null; 
  2 OutputStream os = null; 
  3 InputStream is = null; 
  4 try { 
  5 // url: 
  6 conn = (SocketConnection) Connector.open("socket://10.0.0.172:", Connector.READ_WRITE, true); 
  7 conn.setSocketOption(SocketConnection.DELAY, 0); 
  8 conn.setSocketOption(SocketConnection.KEEPALIVE, 300); 
  9 
  10 // 发送和回复的请求 
  11 os = conn.openDataOutputStream(); 
  12 is = conn.openDataInputStream(); 
  13 
  14 // 在此我们使用HTTP 1.0,HTTP 1.1自己还需要处理chunk,比较麻烦 
  15  reqStr = 
  16 "GET \r\n" + 
  17 ": ebs.95559.com.cn:443\r\n" + 
  18 "User-: FelixBrowser\r\n" + 
  19 "Accept-Charset: utf-8;\r\n" + 
  20 ": close;\r\n" + 
  21 "Accept-Language: zh-cn\r\n\r\n"; 
  22 
  23 os.write(reqStr.getBytes()); 
  24 os.flush(); 
  25 
  26 .out.println("Response Stream:"); 
  27 byte[] buf = new byte[128]; 
  28 while (true) { 
  29  availSize = is.read(buf, 0, buf.length); 
  30 if (availSize == -1) { 
  31 break; 
  32 } 
  33 System.out.println(new String(buf, 0, availSize)); 
  34 } 
  35 } catch (Exception ex) { 
  36 ex.printStackTrace(); 
  37 } finally { 
  38 if (is != null) { 
  39 try { 
  40 is.close(); 
  41 } catch (IOException ex) { 
   ex.printStackTrace(); 
  43 } 
  44 } 
  45 
  46 if (os != null) { 
  47 try { 
  48 os.close(); 
  49 } catch (IOException ex) { 
  50 ex.printStackTrace(); 
  51 } 
  52 } 
  53 
  54 if (conn != null) { 
  55 try { 
  56 conn.close(); 
  57 } catch (IOException ex) { 
  58 ex.printStackTrace(); 
  59 } 
  60 } 
  61 } 
  62

 

  输出结果:

  image

  OK,这就是我们想要的结果。

  封装并重构

  平时我们用习惯了HttpConnection,对于使用SocketConnection访问HTTP来说,太多的设置和属性拼凑给编码带来了不少麻烦。在完善J2MXHTML浏览器时,我将Socket访问HTTP这一块代码封装成一个类SocketHttpConnection,此类继承自HttpConnection,实现了接口方法。

  并且,我还构建了一个工厂类,可以通过枚举的方式创建SocketHttpConnection和纯HttpConnection,有工厂创建的类还可以制定是以代理的方式连接还是直连。在此,我将代码贡献出来给大家。下载地址:这里。

  几个类之间的关系如下:

  无标题

  使用方法很简单:

 


   1 // 请求地址 
  2 String url = ""; 
  3 
  4 // 连接方式:SocketConnection/HttpConnection 
  5 byte connType = HttpConnectionFactory.CONNTYPE_SOCKET_HTTP; 
  6 
  7 // 是否使用代理及代理地址、端口 
  8 boolean isUseProxy = true; 
  9 String proxyHost = "10.0.0.172"; 
  10 int proxyPort = 80; 
  11 
  12 HttpConnection conn = null; 
  13 InputStream is = null; 
  14 try { 
  15 // 调用工厂创建 
  16 conn = HttpConnectionFactory.getConnection(url, connType, isUseProxy, proxyHost, proxyPort); 
  17 
  18 // 像原生HttpConnection一样使用 
  19 int  = conn.getResponseCode(); 
  20 System.out.println("Response Code: " + code); 
  21 
  22 is = conn.openDataInputStream(); 
  23 
  24 System.out.println("Response Stream:"); 
  25 byte[] buf = new byte[128]; 
  26 while (true) { 
  27 int availSize = is.read(buf, 0, buf.length); 
  28 System.out.println(new String(buf, 0, availSize)); 
  29 
  30 if (availSize < buf.length) { 
  31 break; 
  32 } 
  33 } 
  34 } catch (IOException ex) { 
  35 ex.printStackTrace(); 
  36 } 
  37

 

阅读(1733) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~