[英]ONVIF WSDL Based JAX-WS SOAP Web Services - Client is SOAP 1.2 but Server is SOAP 1.1
Issue:问题:
I have created ONVIF WSDL Based Java Client and Server using JAX-WS.我使用 JAX-WS 创建了基于ONVIF WSDL Java 的客户端和服务器。
The problem is that the automatically generated Client is using SOAP 1.2 with HTTP "Content-Type: application:/xml+soap" while the Server is exposing SOAP 1.1 with HTTP "Content-Type: text/xml"问题是自动生成的客户端使用 SOAP 1.2 和 HTTP "Content-Type: application:/xml+soap" 而服务器暴露 SOAP 1.1 和 HTTP "Content-Type: text/xml"
The result is that client fails with media type exception and server throws "Unsupported Content-Type" exception:结果是客户端因媒体类型异常而失败,服务器抛出“Unsupported Content-Type”异常:
Jan. 03, 2023 3:42:55 PM com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit handle
SEVERE: Unsupported Content-Type: application/soap+xml; charset=utf-8;action="http://www.onvif.org/ver10/device/wsdl/GetDeviceInformation" Supported ones are: [text/xml]
com.sun.xml.ws.server.UnsupportedMediaException: Unsupported Content-Type: application/soap+xml; charset=utf-8;action="http://www.onvif.org/ver10/device/wsdl/GetDeviceInformation" Supported ones are: [text/xml]
I have confirmed this by doing direct SOAP invocations via curl.我已经通过 curl 直接调用 SOAP 来确认这一点。
This is successful when "Content-Type: text/xml":当“Content-Type: text/xml”时,这是成功的:
$ curl --verbose http://127.0.0.1:9080/onvif/device_service -H "Content-Type: text/xml" --data '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><getDeviceInformation xmlns="http://www.onvif.org/ver10"></getDeviceInformation></s:Body></s:Envelope>' | xmllint --format -
* Trying 127.0.0.1:9080...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 9080 (#0)
> POST /onvif/device_service HTTP/1.1
> Host: 127.0.0.1:9080
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Type: text/xml
> Content-Length: 273
>
} [273 bytes data]
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Mon, 02 Jan 2023 06:14:40 GMT
< Content-Type: text/xml;charset=utf-8
< Transfer-Encoding: chunked
< Server: Jetty(10.0.12)
<
{ [114 bytes data]
100 1037 0 764 100 273 31538 11269 --:--:-- --:--:-- --:--:-- 45086
* Connection #0 to host 127.0.0.1 left intact
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns3:getDeviceInformationResponse xmlns:ns3="http://www.onvif.org/ver10" xmlns:ns4="http://www.onvif.org/ver10/schema" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:ns6="http://docs.oasis-open.org/wsn/b-2" xmlns:ns7="http://www.w3.org/2005/08/addressing" xmlns:ns8="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns9="http://docs.oasis-open.org/wsn/t-1" xmlns:ns10="http://www.w3.org/2004/08/xop/include" xmlns:ns11="http://www.onvif.org/ver10/device/wsdl" xmlns:ns12="http://www.w3.org/2003/05/soap-envelope">
<arg0>john</arg0>
<arg1>beta</arg1>
<arg2>0.0.1</arg2>
<arg3>1</arg3>
<arg4>hw1</arg4>
</ns3:getDeviceInformationResponse>
</S:Body>
</S:Envelope>
And fails when "Content-Type: application/xml+soap":当“Content-Type: application/xml+soap”时失败:
$ curl --verbose http://127.0.0.1:9080/onvif/device_service -H "Content-Type: application/xml+soap" --data '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><getDeviceInformation xmlns="http://www.onvif.org/ver10"></getDeviceInformation></s:Body></s:Envelope>' | xmllint --format -
* Trying 127.0.0.1:9080...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 9080 (#0)
> POST /onvif/device_service HTTP/1.1
> Host: 127.0.0.1:9080
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Type: application/xml+soap
> Content-Length: 273
>
} [273 bytes data]
* Mark bundle as not supporting multiuse
< HTTP/1.1 415 Unsupported Media Type
< Date: Mon, 02 Jan 2023 06:19:50 GMT
< Transfer-Encoding: chunked
< Server: Jetty(10.0.12)
<
{ [5 bytes data]
100 273 0 0 100 273 0 5812 --:--:-- --:--:-- --:--:-- 5934
* Connection #0 to host 127.0.0.1 left intact
-:1: parser error : Document is empty
^
Environment is:环境是:
JAX-WS Version: JAX-WS 版本:
I have tested with both Java EE & Jakarta EE and they both show the same SOAP 1.1/1.2 Asymmetry for client and server我已经对 Java EE 和 Jakarta EE 进行了测试,它们都显示了相同的 SOAP 1.1/1.2 客户端和服务器的不对称性
Here is server code which just boiler plate using the generated code where这是服务器代码,它只是使用生成的代码的样板
JaxDeviceImpl device = new JaxDeviceImpl();
Is derived from WSDL JAX-WS generated "Device" Server Interface class (WSDL below):源自 WSDL JAX-WS 生成的“设备”服务器接口 class(下面的 WSDL):
/**
@what Embedded Jetty JAVAX JAX-WS Device Simulator
@note: See Eclipse Jetty: Programming Guide
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.eclipse.jetty.server.Server;
import javax.xml.ws.Endpoint;
import onvif_relay.service.JaxDeviceImpl;
import fence.util.ConfigurationData;
public class EmbeddedJettyJaxDevice {
public static void main(String[] args) throws Exception {
ConfigurationData confData = new ConfigurationData(args);
String srvPort = confData.getItem("onvif-device", "port");
String port = confData.getItem("onvif-device", "device-port");
String request = confData.getItem("onvif-device", "request");
try {
System.out.println("Starting the Jetty server on port: " + srvPort + " onvif mgt on: " + port);
Server server = new Server(Integer.parseInt(srvPort));
JaxDeviceImpl device = new JaxDeviceImpl();
// System.setProperty("com.sun.net.httpserver.HttpServerProvider", "org.eclipse.jetty.http.spi.JettyHttpServerProvider");
// System.setProperty("jakarta.xml.ws.spi.Provider", "org.eclipse.jetty.http.spi.JettyHttpServerProvider");
// System.setProperty("javax.xml.ws.spi.Provider", "org.eclipse.jetty.http.spi.JettyHttpServerProvider");
String uri = "http://127.0.0.1:" + port + request;
// Endpoint ep = Endpoint.create(uri, device);
Endpoint ep = Endpoint.publish(uri, device);
server.start();
// consoleLoop(DevManager);
server.join();
System.out.println("Stopped the simple server...");
} catch (Exception ex) {
ex.printStackTrace();
}
}
Service WSDL:客服WSDL:
<?xml version="1.0" encoding="utf-8" ?>
<wsdl:definitions name="onvif_device"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
targetNamespace="http://www.onvif.org/ver10">
<wsdl:import namespace="http://www.onvif.org/ver10/device/wsdl"
location="../ver10/device/wsdl/devicemgmt.wsdl"/>
<wsdl:import namespace="http://www.onvif.org/ver10/media/wsdl"
location="../ver10/media/wsdl/media.wsdl"/>
<wsdl:service name="DeviceService">
<wsdl:documentation>ONVIF - Device</wsdl:documentation>
<!-- wsdl:port name="Device" binding="tns:DeviceBinding" -->
<wsdl:port name="DevicePort" binding="tds:DeviceBinding">
<soap:address location="http://127.0.0.1/onvif/device_service"/>
</wsdl:port>
</wsdl:service>
<!-- wsdl:service name="MediaService">
<wsdl:documentation>ONVIF - Media</wsdl:documentation>
<!- wsdl:port name="Device" binding="tns:MediaBinding" ->
<wsdl:port name="MediaPort" binding="trt:MediaBinding">
<soap:address location="http://127.0.0.1/onvif/device_service"/>
</wsdl:port>
</wsdl:service -->
</wsdl:definitions>
Full code set for both test client and server is posted via github测试客户端和服务器的完整代码集通过github发布
Expectation:期待:
Expectation is that automatically generated JAX-WS code would work transparently between Client / Server.期望自动生成的 JAX-WS 代码将在客户端/服务器之间透明地工作。
NOTE: The current Jakarta XML Web Services specification (Version 3.0) appears to be ambiguous on SOAP 1.1/1.2 support:注意:当前Jakarta XML Web 服务规范(版本 3.0)似乎对 SOAP 1.1/1.2 支持不明确:
What I tried:我尝试了什么:
Tried using:尝试使用:
Testing with generated Client / Server and via direct curl invocation.使用生成的客户端/服务器并通过直接 curl 调用进行测试。
Always get the same result of client (SOAP 1.2) and Server (SOAP 1.1).始终获得客户端 (SOAP 1.2) 和服务器 (SOAP 1.1) 相同的结果。
NOTE #1: as the underlying WSDL is from ONVIF I do not have option of changing WSDL,注意#1:由于基础 WSDL 来自 ONVIF,我没有更改 WSDL 的选项,
Questions:问题:
sDoing further investigation on this I found that the ONVIF SOAP Binding URL: http://schemas.xmlsoap.org/soap/http get redirected to dead end.对此进行进一步调查,我发现 ONVIF SOAP Binding URL: http://schemas.xmlsoap.org/soap/http被重定向到死胡同。
Here is snippet from devicemgmt.wsdl这是来自 devicemgmt.wsdl 的片段
<wsdl:binding name="DeviceBinding" type="tds:Device">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetServices">
<soap:operation soapAction="http://www.onvif.org/ver10/device/wsdl/GetServices"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
I am not sure if this is root cause of problem, but found that I could work around it by changing the server EndPoint create/publish code to it explicitly used SOAP 1.2 / HTTP binding:我不确定这是否是问题的根本原因,但发现我可以通过将服务器 EndPoint 创建/发布代码更改为明确使用 SOAP 1.2 / HTTP 绑定来解决它:
String soapver = SOAPBinding.SOAP11HTTP_BINDING;
if (ver.equals("12"))
soapver = SOAPBinding.SOAP12HTTP_BINDING;
String uri = "http://127.0.0.1:" + port + request;
Endpoint ep = Endpoint.create(soapver, device);
ep.publish(uri);
I have committed update to example and confirmed that ONVIF Device Simulator is now serving SOAP 1.2/HTTP as per ONVIF Specification.我已承诺更新示例并确认 ONVIF 设备模拟器现在根据 ONVIF 规范提供 SOAP 1.2/HTTP 服务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.