[size=x-large]用MTOM在WCF和CXF之间传数据[/size]
MTOM是一种机制,用来以原始字节形式传输包含SOAP消息的较大二进制附件,从而使所传输的消息较小。
如果不用MTOM我们也可以通过WebService传递二进制的文件, 我们先来看看不用MTOM的时候是什么样子的。
[b]服务端[/b]是一个简单的WebService方法, 接受一个byte数组,计算其中的字符数并返回。
[b]客户端[/b]是一个简单的WCF的客户端,读取一个文件把字节传递给count方法
app.config配置如下:
运行一些客户端,就可以让服务器计算字符数了, 我们来看看HTTP请求是什么样子的。
[img]http://dl2.iteye.com/upload/attachment/0086/0791/afb80858-dca7-3004-a4bb-3755c5377acc.png[/img]
Content-Length: 1140036, 传输的内容都是base64编码的。也就是说传给count参数的byte数组被编码成Base64传输的。所以比实际的byte数组要大很多,我们的数组实际是854866, 大了近30%。
HTTP请求的内容
[img]http://dl2.iteye.com/upload/attachment/0086/0793/6daa649f-7d4a-3b42-b104-11b4006ff31d.png[/img]
[size=large]使用MTOM的情况[/size]
服务端
Java接口的参数类型由原来的b[b]yte[][/b]变成[b]DataHanlder[/b], 最重要的是要在前面加一个 @XmlMimeType("application/octet-stream")
配置文件:
添加了一个属性[b]mtom-enabled=true[/b]
加了上面的变化就OK了。
再来看看WCF[b]客户端[/b]的变化
只需要配置文件app.config发生变化就行了
由原来的basicHttpBinding变成customBinding,然后使用[b]mtomMessageEncoding[/b]即可。 这里需要注意一点的是如果不设置messageVersion="Soap11" 默认使用的是Soap1.2 但是在我的环境里CXF对Soap1.2+MTOM的方式支持的好像不是很好。 所有退而求其次用Soap1.1。
最后我们看一下MTOM的方式的HTTP请求到底是什么样子的
[img]http://dl2.iteye.com/upload/attachment/0086/0795/d7eaf4ff-bc24-3599-8a86-4f86790b6ade.png[/img]
我们可以看到Content-Length: 855855 比原来不用MTOM的1140036小了不少。 SOAP消息的样子也和原来的有很大的不同。
[img]http://dl2.iteye.com/upload/attachment/0086/0797/6820167d-da7b-3c66-aebf-17d6ea335e94.png[/img]
本文的源代码在附件中
MTOM是一种机制,用来以原始字节形式传输包含SOAP消息的较大二进制附件,从而使所传输的消息较小。
如果不用MTOM我们也可以通过WebService传递二进制的文件, 我们先来看看不用MTOM的时候是什么样子的。
[b]服务端[/b]是一个简单的WebService方法, 接受一个byte数组,计算其中的字符数并返回。
@WebService
public interface CounterService {
int count(byte[] data);
}
@Service
@WebService(endpointInterface = "com.cccis.ws.CounterService")
public class CounterServiceImpl implements CounterService {
@Override
public int count(byte[] data) {
try {
String text = GZipUtils.decompressText(data, "utf-8");
return text.length();
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
}
<bean id="countServiceImpl" class="com.cccis.ws.CounterServiceImpl" />
<jaxws:endpoint
id="countService"
implementor="#countServiceImpl"
serviceName="countService"
address="/countService" />
[b]客户端[/b]是一个简单的WCF的客户端,读取一个文件把字节传递给count方法
try
{
var service = new ServiceReference1.CounterServiceClient();
var text = File.ReadAllText("c:\\words");
var memoryStream = new MemoryStream();
var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress);
var rawData = Encoding.UTF8.GetBytes(text);
gzipStream.Write(rawData, 0 , rawData.Length);
gzipStream.Close();
var len = service.count(memoryStream.ToArray());
Console.WriteLine("lenght = {0}", len);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
Console.Read();
}
app.config配置如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="countServiceSoapBinding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://192.168.2.3:8080/binder/services/countService"
binding="basicHttpBinding" bindingConfiguration="countServiceSoapBinding"
contract="ServiceReference1.CounterService" name="CounterServiceImplPort" />
</client>
</system.serviceModel>
</configuration>
运行一些客户端,就可以让服务器计算字符数了, 我们来看看HTTP请求是什么样子的。
[img]http://dl2.iteye.com/upload/attachment/0086/0791/afb80858-dca7-3004-a4bb-3755c5377acc.png[/img]
Content-Length: 1140036, 传输的内容都是base64编码的。也就是说传给count参数的byte数组被编码成Base64传输的。所以比实际的byte数组要大很多,我们的数组实际是854866, 大了近30%。
HTTP请求的内容
[img]http://dl2.iteye.com/upload/attachment/0086/0793/6daa649f-7d4a-3b42-b104-11b4006ff31d.png[/img]
[size=large]使用MTOM的情况[/size]
服务端
@WebService
public interface CounterService {
int count(@XmlMimeType("application/octet-stream") DataHandler value);
}
@Service
@WebService(endpointInterface = "com.cccis.ws.CounterService")
public class CounterServiceImpl implements CounterService {
@Override
public int count(DataHandler data) {
try {
String text = GZipUtils.decompressText(data.getInputStream(), "utf-8");
return text.length();
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
}
Java接口的参数类型由原来的b[b]yte[][/b]变成[b]DataHanlder[/b], 最重要的是要在前面加一个 @XmlMimeType("application/octet-stream")
配置文件:
<jaxws:endpoint id="countService" implementor="#countServiceImpl"
serviceName="countService" address="/countService">
<jaxws:properties>
<entry key="mtom-enabled" value="true" />
</jaxws:properties>
</jaxws:endpoint>
添加了一个属性[b]mtom-enabled=true[/b]
加了上面的变化就OK了。
再来看看WCF[b]客户端[/b]的变化
只需要配置文件app.config发生变化就行了
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="countServiceSoapBinding">
<mtomMessageEncoding messageVersion="Soap11"></mtomMessageEncoding>
<httpTransport/>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://192.168.2.3:8080/binder/services/countService"
binding="customBinding" bindingConfiguration="countServiceSoapBinding"
contract="ServiceReference1.CounterService" name="CounterServiceImplPort" />
</client>
</system.serviceModel>
</configuration>
由原来的basicHttpBinding变成customBinding,然后使用[b]mtomMessageEncoding[/b]即可。 这里需要注意一点的是如果不设置messageVersion="Soap11" 默认使用的是Soap1.2 但是在我的环境里CXF对Soap1.2+MTOM的方式支持的好像不是很好。 所有退而求其次用Soap1.1。
最后我们看一下MTOM的方式的HTTP请求到底是什么样子的
[img]http://dl2.iteye.com/upload/attachment/0086/0795/d7eaf4ff-bc24-3599-8a86-4f86790b6ade.png[/img]
我们可以看到Content-Length: 855855 比原来不用MTOM的1140036小了不少。 SOAP消息的样子也和原来的有很大的不同。
[img]http://dl2.iteye.com/upload/attachment/0086/0797/6820167d-da7b-3c66-aebf-17d6ea335e94.png[/img]
本文的源代码在附件中