在J2ME中使用Socket通过cmwap接入点访问安全HTTPS

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

所涉及的知识点:

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

2、基于安全套接字的HTTPS

 

尝试方法一:

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

  
  
1 HttpConnection conn = null ;
2 InputStream is = null ;
3 try {
4 // url: https://ebs.95559.com.cn/corporbank/es_logon.jsp
5 conn = (HttpConnection) Connector.open( " http://10.0.0.172:80/corporbank/es_logon.jsp " , Connector.READ, true );
6 String host = " ebs.95559.com.cn " ;
7 conn.setRequestProperty( " x-online-host " , host);
8 conn.setRequestMethod(HttpConnection.GET);
9
10 int code = conn.getResponseCode();
11 System. 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 }
42 }
43

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

 

  
  
Response Code: 502
Response Stream:
<? xml version = " 1.0 " ?>
<! DOCTYPE wml PUBLIC " -//WAPFORUM//DTD WML 1.1//EN " " http://www.wapforum.org/DTD/wml_1.1.xml " >
< wml >< card >
< p >< do type = " prev " name = " Back " label = " Back " >< prev /></ do > Connection to host failed. Check your settings and try again. If the pro
blem persists contact your operator . </ p ></ card ></ wml >

 

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

 

尝试方法二:

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

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

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

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

 

  
  
Response Code: 500
Response Stream:
<? xml version = " 1.0 " ?>
<! DOCTYPE wml PUBLIC " -//WAPFORUM//DTD WML 1.1//EN " " http://www.wapforum.org/DTD/wml_1.1.xml " >
< wml >< card >
< p >< do type = " prev " name = " Back " label = " Back " >< prev /></ do > Your request for a service could not be fulfilled. Please try again or c
ontact your operator if the problem persists. </ p ></ card ></ wml >

 

原因分析:不详。

 

尝试方法三:

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

将代码第5行修改如下:

  
  
conn = (HttpConnection) Connector.open( " https://10.0.0.172:443/corporbank/es_logon.jsp " , 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-online-host”请求头的。

既然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的方式进行代码的编写。

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

 

  
  
1 SocketConnection conn = null ;
2 OutputStream os = null ;
3 InputStream is = null ;
4 try {
5 // url: https://ebs.95559.com.cn/corporbank/es_logon.jsp
6 conn = (SocketConnection) Connector.open( " socket://10.0.0.172:80 " , 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 String reqStr =
16 " GET https://ebs.95559.com.cn/corporbank/es_logon.jsp HTTP/1.0/r/n " +
17 " Host: ebs.95559.com.cn:443/r/n " +
18 " User-Agent: FelixBrowser/r/n " +
19 " Accept-Charset: utf-8;/r/n " +
20 " Connection: close;/r/n " +
21 " Accept-Language: zh-cn/r/n/r/n " ;
22
23 os.write(reqStr.getBytes());
24 os.flush();
25
26 System. out .println( " Response Stream: " );
27 byte [] buf = new byte [ 128 ];
28 while ( true ) {
29 int 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) {
42 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来说,太多的设置和属性拼凑给编码带来了不少麻烦。在完善J2ME-XHTML浏览器时,我将Socket访问HTTP这一块代码封装成一个类SocketHttpConnection,此类继承自HttpConnection,实现了接口方法。

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

几个类之间的关系如下:

无标题

使用方法很简单:

  
  
1 // 请求地址
2 String url = " https://ebs.95559.com.cn/corporbank/es_logon.jsp " ;
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 code = 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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
未来社区的建设背景和需求分析指出,随着智能经济、大数据、人工智能、物联网、区块链、云计算等技术的发展,社区服务正朝着数字化、智能化转型。社区服务渠道由分散向统一融合转变,服务内容由通用庞杂向个性化、服务导向转变。未来社区将构建数字化生态,实现数据在线、组织在线、服务在线、产品智能和决策智能,赋能企业创新,同时注重人才培养和科研平台建设。 规划设计方面,未来社区将基于居民需求,打造以服务为心的社区管理模式。通过统一的服务平台和应用,实现服务内容的整合和优化,提供灵活多样的服务方式,如推送式、订阅式、热点式等。社区将构建数据与应用的良性循环,提高服务效率,同时注重生态优美、绿色低碳、社会和谐,以实现幸福民生和产业发展。 建设运营上,未来社区强调科学规划、以人为本,创新引领、重点突破,统筹推进、整体提升。通过实施院落+社团自治工程,转变政府职能,深化社区自治法制化、信息化,解决社区治理的重点问题。目标是培养有活力的社会组织,提高社区居民参与度和满意度,实现社区治理服务的制度机制创新。 未来社区的数字化解决方案包括信息发布系统、服务系统和管理系统。信息发布系统涵盖公共服务类和社会化服务类信息,提供政策宣传、家政服务、健康医疗咨询等功能。服务系统功能需求包括办事指南、公共服务、社区工作参与互动等,旨在提高社区服务能力。管理系统功能需求则涉及院落管理、社团管理、社工队伍管理等,以实现社区治理的现代化。 最后,未来社区建设注重整合政府、社会组织、企业等多方资源,以提高社区服务的效率和质量。通过建立社区管理服务综合信息平台,提供社区公共服务、社区社会组织管理服务和社区便民服务,实现管理精简、高效、透明,服务快速、便捷。同时,通过培育和发展社区协会、社团等组织,激发社会化组织活力,为居民提供综合性的咨询和服务,促进社区的和谐发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值