tl; dr version:有没有办法强制JAX-WS的严格模式拒绝base64Binary XSD数据类型的无效base64?
更长的版本:我有一个Web服务接收二进制数据,它被映射到XSD类型base64Binary.在测试服务时,我发现JAX-WS在解析Base64字符串时非常宽松.无论我的输入多么无效,我都无法让JAX-WS产生错误.
我创建了一个小型测试服务和客户端来说明问题.它可以或多或少地逐字复制:
服务界面:
@WebService public interface ITest2 { @WebMethod void foo(byte[] bs); }
服务实施和测试:
@WebService(endpointInterface="foo.bar.ITest2") public class Test2 implements ITest2 { private static final String requestTemplate = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:bar=\"http://bar.foo/\">" + "<soapenv:Header/>" + "<soapenv:Body>" + "<bar:foo>" + "<arg0>%s</arg0>" + "</bar:foo>" + "</soapenv:Body>" + "</soapenv:Envelope>"; private static final String[] testVector = { "////==","///==","//==","/==","/==/==/==","<>","=====","%%%///%%%==%%" }; private static PrintWriter pw; static { try { pw = new PrintWriter("/tmp/output"); } catch (FileNotFoundException e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { Endpoint e = Endpoint.publish("http://localhost:54321/foo",new Test2()); URL requestUrl = new URL("http://localhost:54321/foo"); for(String testVal : testVector) { pw.println("[client] >" + testVal + "<"); HttpURLConnection urlc = (HttpURLConnection) requestUrl.openConnection(); urlc.setRequestProperty("Content-Type","text/xml;charset=UTF-8"); urlc.setDoOutput(true); OutputStream out = urlc.getoutputStream(); String request = String.format(requestTemplate,testVal); out.write(request.getBytes()); out.flush(); InputStream in = urlc.getInputStream(); int read = -1; byte[] buf = new byte[1024]; while((read = in.read(buf)) != -1) { System.err.print(new String(buf,read)); } System.err.println(); } pw.flush(); pw.close(); } @Override public void foo(byte[] bs) { String encoded; if(bs == null) { encoded = "<null>"; } else if(bs.length == 0) { encoded = "<empty>"; } else { encoded = new String(Base64.encodeBase64(bs)); } pw.println("[server] >" + encoded + "<"); } }
这会在/ tmp / output中产生以下输出(我使用Jetty,它在控制台上记录了很多,并且不想打扰它):
[client] >////==< [server] ><null>< [client] >///==< [server] ><null>< [client] >/w==< [server] >/w==< [client] >/==< [server] ><null>< [client] >/==/==/==< [server] >/////w==< [client] ><>< [server] ><empty>< [client] >=====< [server] >/w==< [client] >%%%///%%%==%%< [server] >//8=<
所以这是一个完整的混乱.有时我收到null,有时是空字符串,有时垃圾被其他垃圾取代.此外,每个请求都会生成HTTP回复200,因此无人知道出现问题.
我知道您可以通过向Unmarshaller添加模式来强制JAXB验证这一点.由于JAX-WS在内部使用JAXB,我希望有可能为Web服务启用它.有人知道这是否可能以及如何?
我在Ubuntu上使用Oracle Java 1.6.0_24的默认JAX-WS实现.
解决方法
您可以通过在端点实现上添加
com.sun.xml.internal.ws.developer.SchemaValidation
annotation(Test2)在Metro(JAXWS-RI)中启用架构验证.
这会导致表单的SOAP错误:
... <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope"> <faultcode>S:Server</faultcode> <faultstring>com.sun.istack.internal.XMLStreamException2: org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'foo' is not a valid value for 'base64Binary'.</faultstring> ...
从技术上讲,我认为faultcode应该是S:Client,但我知道什么.