如何通過SOAP發(fā)送二進(jìn)制數(shù)據(jù)?
只要web services需要發(fā)送/接受二進(jìn)制數(shù)據(jù)就會遇到。解決辦法也很直接:或者把二進(jìn)制數(shù)據(jù)通過Base64轉(zhuǎn)到文本,或者通過附件的方式發(fā)送。
Base64方式比較簡單易用,但是生成的文本對應(yīng)二進(jìn)制數(shù)據(jù)體積有三成以上的膨脹。發(fā)送很小二進(jìn)制數(shù)據(jù)的時候可以應(yīng)用,因為簡單,數(shù)據(jù)體積一般也不會超出可接受范圍。
SOAP with Attachments是另一種方式,很類似發(fā)送email的附件。這種做法有效而標(biāo)準(zhǔn),不過它在設(shè)計上有個缺陷,附件并不作為SOAP消息的一部分被發(fā)送,類似在SOAP消息里面?zhèn)鱾€二進(jìn)制數(shù)據(jù)的URL,然后通過這URL得到對應(yīng)的二進(jìn)制數(shù)據(jù)。這可在互操作性上有些問題,比如和WS-Security協(xié)作時可能控制不到外部的二進(jìn)制數(shù)據(jù)。
MTOM(Message Transmission Optimization Mechanism)是在SOAP with Attachment之后一種更好的解決方案。它通過XOP(XML-binary Optimized Packaging)方式來實(shí)現(xiàn)二進(jìn)制數(shù)據(jù)的傳輸。XOP也是將二進(jìn)制數(shù)據(jù)放在XML文檔外面,但它通過在XML文檔中添加XOP:include元素告訴XML處理器使用二進(jìn)制數(shù)據(jù)替換特定的內(nèi)容,這樣就使得二進(jìn)制數(shù)據(jù)的處理方式與文本數(shù)據(jù)的處理方式一致。
下面的代碼片段是簡單的用法示例片段:
Server端代碼:
OMFactory messageFactory = OMAbstractFactory.getOMFactory();
OMNamespace ns = messageFactory.createOMNamespace("urn:foo" , "foo");
OMElement binEle = messageFactory.createOMElement("payload",ns);
File att = new File("someBinaryData");
log.info("is attachement exist? = " + att.exists());
FileDataSource src = new FileDataSource(att);
DataHandler handler = new DataHandler(src);
OMText textNode = messageFactory.createOMText(handler, true);
binEle.addChild(textNode);
element.addChild(binEle);
如果要禁用MTOM,只要在對應(yīng)節(jié)點(diǎn)加上
textNode.setOptimize(false);
就可以了,Axis2將使用Base64編碼來處理二進(jìn)制數(shù)據(jù)。
Client代碼:
設(shè)置客戶端支持MTOM:
ServiceClient wsClient = new ServiceClient();
Options clientOptions = new Options();
clientOptions.setTo(new EndpointReference("http://some/service"));
clientOptions.setAction("foo");
clientOptions.setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE); // enable MTOM
wsClient.setOptions(clientOptions);
取得二進(jìn)制數(shù)據(jù)的方法
OMElement dataElement = result.getFirstChildWithName(new QName("urn:foo", "payload"));
OMText dataNode = (OMText) dataElement.getFirstOMChild();
DataHandler handler = (DataHandler) dataNode.getDataHandler();
InputStream is = handler.getDataSource().getInputStream();
Client通過MTOM傳輸二進(jìn)制數(shù)據(jù)到Server端的方法與Server端類似,只不過是把帶有二進(jìn)制數(shù)據(jù)的節(jié)點(diǎn)添加到要發(fā)送出去的OMElement上。
Axis2配置
在axis2.xml里面修改enableMTOM為true,默認(rèn)是false。
<parameter name="enableMTOM">true</parameter>
注:在應(yīng)用MTOM傳輸二進(jìn)制數(shù)據(jù)時,可以注意到HTTP頭里面的消息類型是messageType=application/xop+xml。