Gangmax Blog

Glassfish 2.1 IllegalCharsetNameException: "utf-8" error when calling a web service

我们的应用运行在Glassfish 2.1上,调用了其他系统的web service,我们使用的是JAX-WS的web service实现。之前一直都没有问题。

但是今天突然发现同样的代码调用web service时会有以下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
javax.xml.ws.soap.SOAPFaultException: java.nio.charset.IllegalCharsetNameException: "utf-8"
at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:189)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:122)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
at $Proxy339.searchIRByAssignedGroup(Unknown Source)
at com.oracle.tis.kaiser.wsclient.QueryServiceDelegate.findUnsynchronized(QueryServiceDelegate.java:29)
at com.oracle.tis.kaiser.RemoteKaiserIncidentTicketRepository.findUnSynchronized(RemoteKaiserIncidentTicketRepository.java:76)
at com.oracle.tis.kaiser.KaiserIncidentTicketProducer.produce(KaiserIncidentTicketProducer.java:27)
at com.oracle.tis.AbstractSynchronizer.synchronize(AbstractSynchronizer.java:24)
at com.oracle.tis.job.SynchronizerQuartzJobBean.executeInternal(SynchronizerQuartzJobBean.java:30)
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)

同样的代码,昨天可以运行,今天就有问题。首先值得怀疑的是对方系统是否有什么变更。但是我发现调用同样的一个web service,使用glassfish和unit test调用就有上面的异常,但是用SoapUI调用就一切正常,这就怪了。唯一的解释是:SoapUI调用和GF/UT调用有某种差异。但是这个差异是什么呢?

折腾了一下午,我想到了找到这种差异的办法:就是使用http sniffer工具,查看具体的http请求的内容到底有何差别。通过查询,我使用了tcpdump这个工具,具体的命令是:

1
sudo tcpdump -n -i eth0 -s 0 -w - src or dst 10.28.14.239 #Web service host IP address.

通过该命令的输出可以看到SoapUI的http请求如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST /arsys/services/ARService?server=remedyqa.crdc.abcde.org&webService=HPD_HelpDesk_Query_IR_PR HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "urn:HPD_HelpDesk_Query_IR_PR/SearchIRByAssignedGroup"
User-Agent: Jakarta Commons-HttpClient/3.1
Host: 10.28.14.239:9085
Content-Length: 536

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:HPD_HelpDesk_Query_IR_PR">
<soapenv:Header>
<urn:AuthenticationInfo>
<urn:userName>WSWEBSUN</urn:userName>
<urn:password>Kaiser22</urn:password>
</urn:AuthenticationInfo>
</soapenv:Header>
<soapenv:Body>
<urn:SearchIRByAssignedGroup>
<urn:Group>ORACLE EBONDING</urn:Group>
<urn:Status>Assigned</urn:Status>
</urn:SearchIRByAssignedGroup>
</soapenv:Body>
</soapenv:Envelope>

而GF/UT的http请求如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /arsys/services/ARService?server=remedyqa.crdc.kp.org&webService=HPD_HelpDesk_Query_IR_PR HTTP/1.1
Content-type: text/xml;charset="utf-8"
Soapaction: "urn:HPD_HelpDesk_Query_IR_PR/SearchIRByAssignedGroup"
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: JAX-WS RI 2.1.6 in JDK 6
Host: 10.28.14.239:9085
Connection: keep-alive
Content-Length: 469

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:HPD_HelpDesk_Query_IR_PR">
<soapenv:Header>
<urn:AuthenticationInfo>
<urn:userName>WSWEBSUN</urn:userName>
<urn:password>Kaiser22</urn:password>
</urn:AuthenticationInfo>
</soapenv:Header>
<soapenv:Body>
<urn:SearchIRByAssignedGroup>
<urn:Group>ORACLE EBONDING</urn:Group>
<urn:Status>Assigned</urn:Status>
</urn:SearchIRByAssignedGroup>
</soapenv:Body>
</soapenv:Envelope>

问题就出在GF/UT请求的第2行中的带双引号的”utf-8”,注意和SoapUI请求的第3行进行比较:后者是没有双引号的。这就是exception中报的错误。可见是因为http header中Content-Type内容有带双引号的”utf-8”导致的。再看第5行:

1
User-Agent: JAX-WS RI 2.1.6 in JDK 6

和SoapUI请求的第5行比较:

1
User-Agent: Jakarta Commons-HttpClient/3.1

也不相同:因此猜想带引号的这种实现正是由”JAX-WS RI 2.1.6”引入的。

按照这个思路google,得到了这个”JAX-WS 2.1.7”的一个bug,这个问题就是我们遇到的问题。该bug已经在2.2版本中解决。那么,解决改问题的思路就是要使用JAX-WS 2.2之后的版本。

首先想到的方法是在maven build的时候,将JAX-WS 2.2版本的jar文件打包到war中去。但是后来发现,这个方法只能解决UT中的错误,实际部署到GF中之后并不生效,怀疑是因为GF会加载自己的JAX-WS jar文件,而不是war里面的。然后搜索到:将GF中的metro升级到2.1(Metro 2.1里面包含JAX-WS 2.3),就可以解决问题。具体的升级方法在这里

这个问题的原因应该是这样的:首先,是因为对方的web service发生了某些变化,比如app server升级之类的,导致原来可以正常使用的带双引号的”utf-8”的”Content-Type”不能使用了。不能改变对方,那只能我们自己这边想办法修改这个问题了,遇到JAX-WS这种框架的bug,还真是郁闷。好在找到了最终的结论和解决的方法,没有白忙。

PS:后来经过询问,发现这个问题确实是由于对方系统的变更引入的。对方最近降级了他们的application server,从Websphere 6.1 downgrade to Websphere 5.1,而我们发现的这个问题,正是Websphere 5.1的一个defect,详情参考这里

Comments