如何为 JAX-WS Web 服务客户端设置超时?

Posted

技术标签:

【中文标题】如何为 JAX-WS Web 服务客户端设置超时?【英文标题】:How do I set the timeout for a JAX-WS webservice client? 【发布时间】:2011-01-10 01:44:34 【问题描述】:

我使用 JAXWS-RI 2.1 为我的 Web 服务创建了一个基于 WSDL 的接口。我可以毫无问题地与 Web 服务交互,但无法指定向 Web 服务发送请求的超时时间。如果由于某种原因它没有响应客户端似乎永远在旋转它的***。

四处寻找发现我可能应该尝试做这样的事情:

((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.ws.request.timeout", 10000);
((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.ws.connect.timeout", 10000);

我还发现,根据您拥有的 JAXWS-RI 版本,您可能需要设置这些属性:

((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 10000);
((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", 10000);

我的问题是,无论以上哪一个是正确的,我都不知道在哪里可以做到这一点。我所拥有的只是一个 Service 子类,它实现了 Web 服务的自动生成接口,并且在实例化时,如果 WSDL 没有响应,那么设置属性已经太晚了:

MyWebServiceSoap soap;
MyWebService service = new MyWebService("http://www.google.com");
soap = service.getMyWebServiceSoap();
soap.sendRequestToMyWebService();

谁能指出我正确的方向?!

【问题讨论】:

我想我没有答案给你,但你的问题帮助我解决了我的问题。我知道 com.sun.xml.ws.request.timeout 属性,但不知道 com.sun.xml.internal.ws.request.timeout 之一。 @RonTuffin 我认为internal 是遗留的,也可能是非内部的。我想在未来,以javax.xml.ws 开头的会成为标准。找出哪个是正确的一个好方法是在你的项目中搜索一个名为JAXWSProperties 的类,并且正确的属性就在那里。您甚至可以从那里导入它,这样如果您更改实现,您将收到更改通知,而不是像我在切换到 Jakarta 以从 Java 8 向上升级时发生的那样功能中断:-) 【参考方案1】:

我知道这已经过时并且在其他地方得到了回答,但希望这可以解决这个问题。我不确定您为什么要动态下载 WSDL 但系统属性:

sun.net.client.defaultConnectTimeout (default: -1 (forever))
sun.net.client.defaultReadTimeout (default: -1 (forever))

应该适用于使用 JAX-WS 使用的 HttpURLConnection 进行的所有读取和连接。如果您从远程位置获取 WSDL,这应该可以解决您的问题 - 但本地磁盘上的文件可能更好!

接下来,如果您想为特定服务设置超时,一旦您创建了代理,您需要将其转换为 BindingProvider(您已经知道),获取请求上下文并设置您的属性。在线 JAX-WS 文档是错误的,这些是正确的属性名称(嗯,它们对我有用)。

MyInterface myInterface = new MyInterfaceService().getMyInterfaceSOAP();
Map<String, Object> requestContext = ((BindingProvider)myInterface).getRequestContext();
requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 3000); // Timeout in millis
requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 1000); // Timeout in millis
myInterface.callMyRemoteMethodWith(myParameter);

当然,这是一种可怕的做事方式,我会创建一个很好的工厂来生产这些绑定提供程序,这些提供程序可以注入你想要的超时时间。

【讨论】:

请注意,REQUEST_TIMEOUT / CONNECT_TIMEOUT 属性实际上继承自 SUN 内部类 com.sun.xml.internal.ws.developer.JAXWSProperties 和(至少在 32 位 Linux 上)javac 1.6。 0_27 和 javac 1.7.0_03 无法编译此代码(类似于 bugs.sun.com/view_bug.do?bug_id=6544224 )...您需要将 -XDignore.symbol.file 传递给 javac 以使其工作。 什么不起作用?我只是仔细检查了这个,它对我有用。 只是确认我刚刚将它与 JAX-WS RI 2.2.8 和 JDK 1.7 一起使用,它工作得很好。谢谢! 不应使用在其完全限定名称中具有“内部”的类和参数,因为它们依赖于供应商,因此不能在不同的 JDK 实现之间移植。以 jax-ws 参数为例,对应的非内部属性存在于 com.sun.xml.ws.client.BindingProviderProperties 类中。 @Matt1776 是的,当然它丢失了:虽然 JAX-WS 是一个 API 规范,但您需要一个库实现,在本例中为 jaxws-ri.jar 或 jaxws-rt.jar,这不是一部分的JDK。您只需下载并将其添加到您的 ptoject 中,您就可以使用这些属性。【参考方案2】:

已接受答案中的属性对我不起作用,可能是因为我使用的是 JAX-WS 的 JBoss 实现?

使用一组不同的属性(在 JBoss JAX-WS User Guide 中找到)使其工作:

//Set timeout until a connection is established
((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", "6000");

//Set timeout until the response is received
((BindingProvider) port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", "1000");

【讨论】:

我没有使用 JBoss,但只有这条评论中的属性对我有用,没有其他的。 属性名称取决于 JAX-WS 实现。可以在此处找到列表:java.net/jira/browse/JAX_WS-1166 java.net 链接已损坏。 github.com/javaee/metro-jax-ws/issues/1166 这在 Wildfly 18 和 java 11 上对我有用【参考方案3】:

这是我的工作解决方案:

// --------------------------
// SOAP Message creation
// --------------------------
SOAPMessage sm = MessageFactory.newInstance().createMessage();
sm.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
sm.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");

SOAPPart sp = sm.getSOAPPart();
SOAPEnvelope se = sp.getEnvelope();
se.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
se.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");

SOAPBody sb = sm.getSOAPBody();
// 
// Add all input fields here ...
// 

SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
// -----------------------------------
// URL creation with TimeOut connexion
// -----------------------------------
URL endpoint = new URL(null,
                      "http://myDomain/myWebService.php",
                    new URLStreamHandler()  // Anonymous (inline) class
                    @Override
                    protected URLConnection openConnection(URL url) throws IOException 
                    URL clone_url = new URL(url.toString());
                    HttpURLConnection clone_urlconnection = (HttpURLConnection) clone_url.openConnection();
                    // TimeOut settings
                    clone_urlconnection.setConnectTimeout(10000);
                    clone_urlconnection.setReadTimeout(10000);
                    return(clone_urlconnection);
                    
                );


try 
    // -----------------
    // Send SOAP message
    // -----------------
    SOAPMessage retour = connection.call(sm, endpoint);

catch(Exception e) 
    if ((e instanceof com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl) && (e.getCause()!=null) && (e.getCause().getCause()!=null) && (e.getCause().getCause().getCause()!=null)) 
        System.err.println("[" + e + "] Error sending SOAP message. Initial error cause = " + e.getCause().getCause().getCause());
    
    else 
        System.err.println("[" + e + "] Error sending SOAP message.");

    

【讨论】:

这些配置是否等同于“javax.xml.ws.client.connectionTimeout”和“javax.xml.ws.client.receiveTimeout”?? 对我来说,这个解决方案不适用于 weblogic。在普通的 java 类中运行时,这工作正常。知道可能是什么原因,因为我没有看到任何错误堆栈。 使用com.sun.xml.internal.ws.request.timeoutURLConnection clone_urlconnection = clone_url.openConnection(); 代替HttpURLConnection clone_urlconnection = (HttpURLConnection) clone_url.openConnection(); 为我工作【参考方案4】:
ProxyWs proxy = (ProxyWs) factory.create();
Client client = ClientProxy.getClient(proxy);
HTTPConduit http = (HTTPConduit) client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
http.setClient(httpClientPolicy);

这对我有用。

【讨论】:

谢谢!对我来说,这是一个非常简单的方法 虽然这使用了 Apache CXF 类,但最好在答案中添加它。 CXF jar 包含它们的链接也会有很大帮助。 @JBert 我同意。我几年前回答过这个,不记得了。随意编辑答案。【参考方案5】:

如果您在 JDK6 上使用 JAX-WS,请使用以下属性:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout

【讨论】:

System.setProperty("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty("com.sun.xml.internal.ws.request.timeout", "300") 为我工作。 在某些情况下,您不知道运行时将使用哪个 JAXWS 版本(内部或独立)。两者非常兼容,除了这个超时功能。键是不同的(com.sun.xml.internal.ws.connect.timeout vs com.sun.xml.ws.connect.timeout)以及定义它们的类(或接口)(com.sun.xml.internal.ws.developer.JAXWSProperties/com.sun.xml.internal.ws.client.BindingProviderProperties vs com.sun.xml.ws.developer.JAXWSProperties/com.sun.xml.ws.client.BindingProviderProperties)。我最好的想法是设置两者,使用文字值作为键。【参考方案6】:

如果您的应用服务器是 WebLogic(对我来说是 10.3.6),那么负责超时的属性是:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout

【讨论】:

【参考方案7】:

不确定这是否对您的上下文有帮助...

soap 对象可以转换为 BindingProvider 吗?

MyWebServiceSoap soap;
MyWebService service = new MyWebService("http://www.google.com");
soap = service.getMyWebServiceSoap();
// set timeouts here
((BindingProvider)soap).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 10000);
    soap.sendRequestToMyWebService();

另一方面,如果您想在 MyWebService 对象的初始化时设置超时,那么这将无济于事。

当我想使单个 WebService 调用超时时,这对我有用。

【讨论】:

【参考方案8】:

在实例化 SEI 时避免缓慢检索远程 WSDL 的最简单方法是在运行时不从远程服务端点检索 WSDL。

这意味着您必须在服务提供商进行有影响的更改时更新您的本地 WSDL 副本,但这也意味着您必须在服务提供商进行有影响的更改时更新您的本地副本。

当我生成我的客户端存根时,我告诉 JAX-WS 运行时以这样一种方式对 SEI 进行注释,以便它将从类路径上的预定位置读取 WSDL。默认情况下,该位置相对于 Service SEI 的包位置


<wsimport
    sourcedestdir="$dao.helter.dir/build/generated"
    destdir="$dao.helter.dir/build/bin/generated"
    wsdl="$dao.helter.dir/src/resources/schema/helter/helterHttpServices.wsdl"
    wsdlLocation="./wsdl/helterHttpServices.wsdl"
    package="com.helter.esp.dao.helter.jaxws"
    >
    <binding dir="$dao.helter.dir/src/resources/schema/helter" includes="*.xsd"/>
</wsimport>
<copy todir="$dao.helter.dir/build/bin/generated/com/helter/esp/dao/helter/jaxws/wsdl">
    <fileset dir="$dao.helter.dir/src/resources/schema/helter" includes="*" />
</copy>

wsldLocation 属性告诉 SEI 在哪里可以找到 WSDL,并且副本确保 wsdl(以及支持 xsd.. 等)在正确的位置。

由于位置是相对于 SEI 的包位置,我们创建一个名为 wsdl 的新子包(目录),并将所有 wsdl 工件复制到那里。

此时您要做的就是确保在创建客户端存根工件 jar 文件时除了所有 *.class 之外还包括所有 *.wsdl、*.xsd。

(如果您好奇,@webserviceClient 注释是这个 wsdl 位置在 java 代码中实际设置的位置

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")

【讨论】:

以上是关于如何为 JAX-WS Web 服务客户端设置超时?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 oAuth 2.0 保护 apache cxf webservice(jax-ws)

如何为加载已关闭的外部 javascript 文件设置超时

JAX-WS 客户端:跨多个服务维护会话/cookie

如何测试 JAX-WS 连接超时

为 JAX-RPC Web 服务生成 JAX-WS 客户端存根?

如何为 AndroidAsync websockets 设置超时?