https web service(转)

最近一个项目,接口包含了web service接口,想想很简单的(以前都没有使用ssl,没想到ssl会遇到一些麻烦),就是调用别人的web service,开始用了xfire来做,通过wsdl很快生成了代码,写好测试类,运行,错误出现了 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 这样的异常,初步判断是ssl的问题。找了xfire的文档,发现,如果要使用https的连接,需要相应的处理。于是在代码前加入Java代码
ProtocolSocketFactory easy = new EasySSLProtocolSocketFactory();  
        Protocol protocol = new Protocol("https", easy, 80);  
        Protocol.registerProtocol("https", protocol); 

ProtocolSocketFactory easy = new EasySSLProtocolSocketFactory();
Protocol protocol = new Protocol("https", easy, 80);
Protocol.registerProtocol("https", protocol);
再运行刚才的错误消失了,又出现了新的问题org.codehaus.xfire.fault.XFireFault: No Deserializer found to deserialize a 'urn:pronto.creditReserveAPI.ver1:ns2:in0' using encoding style 'null'.不知道什么原因,google的大半天也没有解决(用axis调通后怀疑xfire生成的问题,不知道那位大侠遇到过如此问题,不吝指 教),最后没有办法,决定换axis试试,生成代码也很顺利,同样遇到https的问题,这次的解决办法是参考了 http://wwwww.iteye.com/blog/94854的文章(在此谢谢了,帮了个大忙)(从ie导出证书,并在程序设置 System.setProperty("javax.net.ssl.trustStore","D:/test/urltest/crt");或者在 运行java时加入参数:-Djavax.net.ssl.trustStore=D:/test/urltest/crt. ),配置了客户端证书,然后测试,终于测试顺利通过。后话,在axis中出现PKIX path building failed的错误的时候,不知道还有没有别的办法进行处理,有时间再研究这个问题了。btw:(O'Reilly 的java security 第2版,里面的接口已经过时了,但是原理讲的很清楚)



java调webService太正常了。。。
在调用https的webService的时候几种常用的方法会出现安全错误,很多人说的是在jre里面装证书。。。那也太郁闷了吧
这里提供一种不用证书的方式


对方webService提供的接口,这个你应该要知道的吧,不知道的话就wsdl自己还原
Java代码
/** 
* XXX的webService接口声明 
* 包括两个方法: 
* 1.根据XXX提供的license取得检查的xml模板 
* 2.根据XXX提供的license和包装好的xml模板,取得检查结果 
* @author bo 
* @version $Id: XXXInterface.java,v 0.1 2009-9-1 上午09:59:05 bo Exp $ 
*/ 
public interface XXXInterface{  
    // 核查方法  
    public String xxxCheck(String inLicense, String inConditions);  
 
    // 取得条件文件模板  
    public String xxxGetCondition(String inLicense) throws Exception;  


/**
* XXX的webService接口声明
* 包括两个方法:
* 1.根据XXX提供的license取得检查的xml模板
* 2.根据XXX提供的license和包装好的xml模板,取得检查结果
* @author bo
* @version $Id: XXXInterface.java,v 0.1 2009-9-1 上午09:59:05 bo Exp $
*/
public interface XXXInterface{
    // 核查方法
    public String xxxCheck(String inLicense, String inConditions);

    // 取得条件文件模板
    public String xxxGetCondition(String inLicense) throws Exception;
}


Java代码
    /** xxxx网webService地址 */ 
    private static final String SERVICE_URL       = "https://api.xxx.org.cn/ws/services/";  
 
    /** xxx网webService的名称空间 */ 
    private static final String SERVICE_NAMESPACE = "http://api.xxx.org.cn/XXXService";  
 
 
    /** xxx网服务名称 */ 
    private static final String SERVICE_NAME      = "xxxServices";  
 
    /** http协议类型 */ 
    private static final String HTTP_TYPE         = "https";  
 
    /** 端口号 */ 
    private static final int    PORT              = 443;  
/** 
     * 初始化xxx的webService调用,设置访问xxx网webService的相关属性 
     */ 
    private void initService() {  
        ProtocolSocketFactory easy = new EasySSLProtocolSocketFactory();  
        Protocol protocol = new Protocol(HTTP_TYPE, easy, PORT);  
        Protocol.registerProtocol(HTTP_TYPE, protocol);  
        Service serviceModel = new ObjectServiceFactory().create(NciicInterface.class,  
            "NciicServices", SERVICE_NAMESPACE, null);  
        try {  
            service = (NciicInterface) new XFireProxyFactory().create(serviceModel, SERVICE_URL  
                                                                                    + SERVICE_NAME);  
        } catch (MalformedURLException e) {  
            logger.error("初始化xx网webService失败," + e);  
        }  
        //设置client的相关属性,设置传输数据的方式  
        Client client = ((XFireProxy) Proxy.getInvocationHandler(service)).getClient();  
        client.addOutHandler(new DOMOutHandler());  
        client.setProperty(CommonsHttpMessageSender.GZIP_ENABLED, Boolean.TRUE);  
        client.setProperty(CommonsHttpMessageSender.DISABLE_EXPECT_CONTINUE, "1");  
        client.setProperty(CommonsHttpMessageSender.HTTP_TIMEOUT, "0");  
    } 

    /** xxxx网webService地址 */
    private static final String SERVICE_URL       = "https://api.xxx.org.cn/ws/services/";

    /** xxx网webService的名称空间 */
    private static final String SERVICE_NAMESPACE = "http://api.xxx.org.cn/XXXService";


    /** xxx网服务名称 */
    private static final String SERVICE_NAME      = "xxxServices";

    /** http协议类型 */
    private static final String HTTP_TYPE         = "https";

    /** 端口号 */
    private static final int    PORT              = 443;
/**
     * 初始化xxx的webService调用,设置访问xxx网webService的相关属性
     */
    private void initService() {
        ProtocolSocketFactory easy = new EasySSLProtocolSocketFactory();
        Protocol protocol = new Protocol(HTTP_TYPE, easy, PORT);
        Protocol.registerProtocol(HTTP_TYPE, protocol);
        Service serviceModel = new ObjectServiceFactory().create(NciicInterface.class,
            "NciicServices", SERVICE_NAMESPACE, null);
        try {
            service = (NciicInterface) new XFireProxyFactory().create(serviceModel, SERVICE_URL
                                                                                    + SERVICE_NAME);
        } catch (MalformedURLException e) {
            logger.error("初始化xx网webService失败," + e);
        }
        //设置client的相关属性,设置传输数据的方式
        Client client = ((XFireProxy) Proxy.getInvocationHandler(service)).getClient();
        client.addOutHandler(new DOMOutHandler());
        client.setProperty(CommonsHttpMessageSender.GZIP_ENABLED, Boolean.TRUE);
        client.setProperty(CommonsHttpMessageSender.DISABLE_EXPECT_CONTINUE, "1");
        client.setProperty(CommonsHttpMessageSender.HTTP_TIMEOUT, "0");
    }


service就相当于将webService给初始化了,然后就可以直接service调用XXXInterface里面的方法了





WebService 是基于SOAP协议传输的,SOAP是以XML文件形式进行信息传输,是明文,这是不安全的,所以我们可以在WebService加上SSL/HTTPS协议来进行数据传输

基于Axis的WebService可以很好的实现,在这里我们使用tomcat服务器

使用JDK自带的工具创建密匙库和信任库。

  1)通过使用以下的命令来创建服务器端的密匙库:
   keytool -genkey -alias Server -keystore server.keystore -keyalg RSA
  输入keystore密码:  strongit
  您的名字与姓氏是什么?
  [Unknown]:  Server
  您的组织单位名称是什么?
  [Unknown]:  ec
  您的组织名称是什么?
  [Unknown]:  ec
  您所在的城市或区域名称是什么?
  [Unknown]:  nanchang
  您所在的州或省份名称是什么?
  [Unknown]:  jiangxi
  该单位的两字母国家代码是什么
  [Unknown]:  CN
CN=Server, OU=ec, O=ec, L=beijing, ST=beijing, C=CN 正确吗?
  [否]:  y

输入<Server>的主密码
        (如果和 keystore 密码相同,按回车):
   以上命令执行完成后,将获得一个名为server.keystore的密匙库。
  
  2)生成客户端的信任库。首先输出RSA证书:
  keytool -export -alias Server -file test_axis.cer -storepass strongit-keystore server.keystore
  然后把RSA证书输入到一个新的信任库文件中。这个信任库被客户端使用,被用来验证服务器端的身份。
  keytool -import -file test_axis.cer -storepass changeit -keystore client.truststore -alias serverkey -noprompt
  以上命令执行完成后,将获得一个名为client.truststore的信任库。
 
  3)同理生成客户端的密匙库client.keystore和服务器端的信任库server.truststore.方便起见给出.bat文件
     gen-cer-store.bat内容如下:
     set SERVER_DN="CN=Server, OU=ec, O=ec, L=nanchang, S=jiangxi, C=CN"
     set CLIENT_DN="CN=Client, OU=ec, O=ec, L=nanchang, S=jiangxi, C=CN"
     set KS_PASS=-storepass strongit
     set KEYINFO=-keyalg RSA

     keytool -genkey -alias Server -dname %SERVER_DN% %KS_PASS% -keystore server.keystore %KEYINFO% -keypass strongit
     keytool -export -alias Server -file test_axis.cer %KS_PASS% -keystore server.keystore
     keytool -import -file test_axis.cer %KS_PASS% -keystore client.truststore -alias serverkey -noprompt

     keytool -genkey -alias Client -dname %CLIENT_DN% %KS_PASS% -keystore client.keystore %KEYINFO% -keypass strongit
     keytool -export -alias Client -file test_axis.cer %KS_PASS% -keystore client.keystore
     keytool -import -file test_axis.cer %KS_PASS% -keystore server.truststore -alias clientkey -noprompt
    
  好的,现在我们就有了四个文件:server.keystore,server.truststore,client.keystore,client.truststore



更改Tomcat的配置文件(server.xml),增加以下部署描述符:(其实里面有,只是被注释掉了)
      <Connector port="8440"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" disableUploadTimeout="true"
               acceptCount="100" scheme="https" secure="true"
               clientAuth="true" keystoreFile="f:\server.keystore" keystorePass="changeit"
                 truststoreFile="f:\server.truststore" truststorePass="changeit"
               sslProtocol="TLS" />

这里主要讲如何使用JDK自带的工具创建密匙库和信任库


文章出处:DIY部落(http://www.diybl.com/course/1_web/webjs/200877/131667.html)





最近在做一个调用webservice的客户端,之前做过,以为很容易,但这过程中遇到的一些问题让我发现自己懂的还是太少。
   webservice的服务端是需要证书认证的,证书已经发给我了,cer格式的,使用java的keytool工具提取证书后,在调用webservice时执行以下语句:
   System.setProperty("javax.net.ssl.trustStore", "xxxx.truststore");
  告诉服务端我客户端是有证书的,目前来看没问题。
   接下来,我用axis2的wsdl2java生成了客户端的代码,结果一执行就出现如下错误:
  org.apache.axis2.AxisFault: [ISS.0088.9125] SOAP request does not conform to the SOAP message model
   在soap的开发文档中查到这个错,是因为请求的soap message格式错误,文档地址:http://documentation.softwareag.com/webmethods/wmsuite7 /Developer/Guides/7-1-1_SOAP_Developers_Guide.pdf(89页)
   这时对方要求我把soap request message发过去,我对webservice只是停留在用的阶段,会用axis,xfire之类的工具写服务端和客户端,但是对soap就是一知半解 了,上网找资料,问同事,折腾了半天,总算把request message找出来了。同事给的方法是用tcp monitor之类的工具,但是webservice是https格式的,不能用,后来在生成的客户端代码里把 SOAPEnvelope.toString()打出来才得到,如下:
  <?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
  <ns1:UPLGenerate xmlns:ns1="http://www.alcatel-lucent.com/webService/WS_UPL">
  <OperationCode>1 </OperationCode>
  <Plant>2 </Plant>
  <QuoteNumber>3 </QuoteNumber>
  <UserID>4 </UserID>
  <IncludePriceType>5 </IncludePriceType>
  </ns1:UPLGenerate>
  </soapenv:Body>
  </soapenv:Envelope>
   其实这个问题的原因是axis2客户端默认的transfer-encoding是chunked,所以在soap 请求报文的body首尾会有两个数字,可以用tcpmon测试一下,.net或者其他一些server是不支持这种模式的,代码中设置一下就可以了,如 下:
  stub._getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED, false);
  周末研究出来的,之前咨询了公司的一个senior,帮我查,也给了我一些建议,非常感谢他!
  现在执行应该没问题了吧,我倒是想,结果又有问题了
  Exception in thread "main" org.apache.axis2.AxisFault: org.apache.axis2.databinding.ADBException: Unexpected subelement xxxxResponse
  at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430)
  这个问题折腾了我三天,在网上查到很多,有的说要用wstx-asl-3.2.1.jar等等,都试了,不通,至少我这边不是因为这个错,很 急,一点头绪没有,后来偶然在stub里把org.apache.axiom.soap.SOAPEnvelope _returnEnv打印出来了,就是_returnEnv.toString(),发现和用soapUI返回的结果不一样,因为这个 webservice是https的,所以不能用tcpmon,这下明白了,因为返回response里的一下元素不是一直有的,但是在wsdl定义里却 没有定义,即没写minOccurs="0",结果用这个wsdl生成的客户端代码如果没取到那些没返回的元素,自然会报错,在wsdl里加上 minOccurs="0",重新生成客户端代码,测试,通过。
   最后一步,部署到websphere上后,执行webservice调用出错:
  java.net.SocketException: Unconnected sockets not implemented
  是证书的问题,花了好几天时间,后来又反复,是因为缺少这个证书的父证书,总之如果在websphere里无法通过host和port得到所有证书,包括从直接使用的证书到证书颁发机构的证书,只有通过导入.cer文件的方法了,问题的根源就在这里:证书!!!
   遇到的问题很烦人,但是收获也不小,这短短几天,让我对webservice的认识加深很多,很惭愧的说,以前只知道用axis等写服务端,然后用wsdl生成客户端,不知道用wsdl还可以生成服务端的。还好有这次机会,我进步了,大家共勉。
最近在做一个调用webservice的客户端,之前做过,以为很容易,但这过程中遇到的一些问题让我发现自己懂的还是太少。 webservice的服务端是需要证书认证的,证书已经发给我了,cer格式的,使用java的keytool工具提取证书后,在调用 webservice时执行以下语句: System.setProperty("javax.net.ssl.trustStore", "xxxx.truststore"); 告诉服务端我客户端是有证书的,目前来看没问题。 接下来,我用axis2的wsdl2java生成了客户端的代码,结果一执行就出现如下错误: org.apache.axis2.AxisFault: [ISS.0088.9125] SOAP request does not conform to the SOAP message model 在soap的开发文档中查到这个错,是因为请求的soap message格式错误,文档地址:http://documentation.softwareag.com/webmethods/wmsuite7 /Developer/Guides/7-1-1_SOAP_Developers_Guide.pdf(89页) 这时对方要求我把soap request message发过去,我对webservice只是停留在用的阶段,会用axis,xfire之类的工具写服务端和客户端,但是对soap就是一知半解 了,上网找资料,问同事,折腾了半天,总算把request message找出来了。同事给的方法是用tcp monitor之类的工具,但是webservice是https格式的,不能用,后来在生成的客户端代码里把 SOAPEnvelope.toString()打出来才得到,如下: <?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <ns1:UPLGenerate xmlns:ns1="http://www.alcatel-lucent.com/webService/WS_UPL"> <OperationCode>1 </OperationCode> <Plant>2 </Plant> <QuoteNumber>3 </QuoteNumber> <UserID>4 </UserID> <IncludePriceType>5 </IncludePriceType> </ns1:UPLGenerate> </soapenv:Body> </soapenv:Envelope> 其实这个问题的原因是axis2客户端默认的transfer-encoding是chunked,所以在soap 请求报文的body首尾会有两个数字,可以用tcpmon测试一下,.net或者其他一些server是不支持这种模式的,代码中设置一下就可以了,如 下: stub._getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED, false); 周末研究出来的,之前咨询了公司的一个senior,帮我查,也给了我一些建议,非常感谢他! 现在执行应该没问题了吧,我倒是想,结果又有问题了 Exception in thread "main" org.apache.axis2.AxisFault: org.apache.axis2.databinding.ADBException: Unexpected subelement xxxxResponse at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430) 这个问题折腾了我三天,在网上查到很多,有的说要用wstx-asl-3.2.1.jar等等,都试了,不通,至少我这边不是因为这个错,很急,一点头绪 没有,后来偶然在stub里把org.apache.axiom.soap.SOAPEnvelope _returnEnv打印出来了,就是_returnEnv.toString(),发现和用soapUI返回的结果不一样,因为这个 webservice是https的,所以不能用tcpmon,这下明白了,因为返回response里的一下元素不是一直有的,但是在wsdl定义里却 没有定义,即没写minOccurs="0",结果用这个wsdl生成的客户端代码如果没取到那些没返回的元素,自然会报错,在wsdl里加上 minOccurs="0",重新生成客户端代码,测试,通过。 最后一步,部署到websphere上后,执行webservice调用出错: java.net.SocketException: Unconnected sockets not implemented 是证书的问题,花了好几天时间,后来又反复,是因为缺少这个证书的父证书,总之如果在websphere里无法通过host和port得到所有证书,包括 从直接使用的证书到证书颁发机构的证书,只有通过导入.cer文件的方法了,问题的根源就在这里:证书!!! 遇到的问题很烦人,但是收获也不小,这短短几天,让我对webservice的认识加深很多,很惭愧的说,以前只知道用axis等写服务端,然后用 wsdl生成客户端,不知道用wsdl还可以生成服务端的。还好有这次机会,我进步了,大家共勉。
http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0504_cowan/0504_cowan.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值