1

I use Netbeans to generate web service client code, client-style JAX-WS, so i can invoke a web service API.

However, when I invoke the web service API, I get the exception: com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 307: Temporary Redirect

Why do I get this? What is the workaround? I know the problem isn't with the web service itself, because I can get responses fine via soapUI and .Net.

4

2 回答 2

0

大约一个月前面临同样的问题。

Web 服务客户端类是使用 Apache CXF 生成的,并且 Web 服务返回 HTTP 状态 307,这导致了相同的异常。

使用属性Follow Redirects设置为的 soapUI 调用相同的 Web 服务方法true是成功的,并返回了所需的数据。

谷歌搜索了一段时间后,似乎没有属性可以为此在 JAX-WS 中启用以下重定向。

因此,以下是当前正在运行的代码,尽管我不确定它是否符合任何标准:

假设生成的客户端类如下所示:

// generated service class
public class MyWebServiceClient extends javax.xml.ws.Service {
    // ...
    private final QName portName = "...";
    // ...
    public RetrieveMyObjects getRetrieveMyObjects() {
        return super.getPort(portName, RetrieveMyObject.class);
    }
    // ...
}

// generated port interface
// annotations here
public interface RetrieveMyObjects {

    // annotations here
    List<MyObject> getAll();

}

现在,在执行以下代码时:

MyWebServiceClient wsClient = new MyWebServiceClient("wsdl/location/url/here.wsdl");
RetrieveMyObjectsPort retrieveMyObjectsPort = wsClient.getRetrieveMyObjects();

wsClientRetrieveMyObjects应该返回既是&javax.xml.ws.BindingProvider接口的实例的实例。JAX-WS 表面上没有任何地方说明,但似乎很多代码都是基于这个事实。可以通过执行以下操作来重新向他/她自己保证:

if(!(retrieveMyObjectsPort instanceof javax.xml.ws.BindingProvider)) {
    throw new RuntimeException("retrieveMyObjectsPort is not instance of " + BindingProvider.class + ". Redirect following as well as authentication is not possible");
}

现在,当我们确定这retrieveMyObjectsPort是一个实例时,javax.xml.ws.BindingProvider我们可以向它发送普通的 HTTP POST 请求,模拟 SOAP 请求(虽然它看起来非常不正确和丑陋,但这适用于我的情况,我在谷歌搜索时没有找到更好的东西)和检查 Web 服务是否会发送重定向状态作为响应:

// defined somewhere before
private static void checkRedirect(final Logger logger, final BindingProvider bindingProvider) {
    try {
        final URL url = new URL((String) bindingProvider.getRequestContext().get(ENDPOINT_ADDRESS_PROPERTY));
        logger.trace("Checking WS redirect: sending plain POST request to {}", url);
        final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setInstanceFollowRedirects(true);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "text/html; charset='UTF-8'");
        connection.setDoOutput(true);

        if(connection.getResponseCode() == 307) {
            final String redirectToUrl = connection.getHeaderField("location");
            logger.trace("Checking WS redirect: setting new endpoint url, plain POST request was redirected with status {} to {}", connection.getResponseCode(), redirectToUrl);
            bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, redirectToUrl);
        }
   } catch(final Exception e) {
       logger.warn("Checking WS redirect: failed", e);
   }
}

// somewhere at the application start
checkRedirect(logger, (BindingProvider) retrieveMyObjectsPort);

现在,这个方法的作用是:它接受这个端口方法将向其发送 SOAP 请求BindingProvider.ENDPOINT_ACCESS_PROPERTYretrieveMyObjectsPorturl,并如上所述发送普通的 HTTP POST 请求。然后它检查响应状态是否为307 - Temporary Redirect(也可能包括其他状态,如 302 或 301),如果是,则获取 Web 服务重定向到的 URL 并为指定端口设置新端点。

在我的情况下,这个checkRedirect方法为每个 Web 服务端口接口调用一次,然后一切似乎都工作正常:

  1. 在 url 上检查重定向,例如http://example.com:50678/restOfUrl
  2. Web 服务重定向到类似 url https://example.com:43578/restOfUrl(请注意存在 Web 服务客户端身份验证) - 端口的端点设置为该 url
  3. 通过该端口执行的下一个 Web 服务请求成功

免责声明:我对 web 服务很陌生,由于缺乏解决这个问题的方法,这是我设法实现的,所以如果这里有问题,请纠正我。

希望这可以帮助

于 2012-03-19T00:22:37.053 回答
0

是的,我知道这篇文章很旧,但我也遇到过类似的错误,我想也许有人会从我的解决方案中受益。
最困扰我的是:

com.sun.xml.ws.client.ClientTransportException: The server sent HTTP status code 200: OK

原来这意味着一个不完整的响应头。显然 jax-ws 进行了某种验证,包括验证 HTTP 标头。而我使用的服务器只是发送一个空头。

'application/soap+xml'添加到Content-Type标题后,它就像一个魅力。

于 2012-11-07T10:51:50.193 回答