Клиент веб-службы Java, сгенерированный в Netbeans - получение Http Status Code 307 - PullRequest
1 голос
/ 27 мая 2011

Я использую Netbeans для генерации клиентского кода веб-службы, JAX-WS, в стиле клиента, поэтому я могу вызывать API веб-службы.

Однако при вызове API веб-службы я получаю исключение: com.sun.xml.internal.ws.client.ClientTransportException: сервер отправил код состояния HTTP 307: временное перенаправление

Почему я получаю это?Какой обходной путь?Я знаю, что проблема не в самом веб-сервисе, потому что я могу нормально получать ответы через soapUI и .Net.

Ответы [ 2 ]

0 голосов
/ 07 ноября 2012

Да, я знаю, что этот пост старый, но у меня были похожие ошибки, и я подумал, что, возможно, кто-то извлечет выгоду из моего решения.
больше всего меня мучает:Который, оказывается, означает неполный заголовок ответа.Очевидно, jax-ws выполняет некоторую проверку, которая также включает проверку заголовков HTTP.И сервер, который я использовал, просто отправлял пустой заголовок.

Он работал как шарм после добавления 'application/soap+xml' в заголовок Content-Type.

0 голосов
/ 19 марта 2012

Столкнулся с той же проблемой около месяца назад.

Классы клиентов веб-службы были созданы с использованием Apache CXF, и веб-служба возвратила HTTP-статус 307, что привело к тому же исключению.

Вызовтот же метод веб-службы, использующий soapUI со свойством Follow Redirects, установленным на 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();

wsClient должен вернуть экземпляр, который является экземпляром RetrieveMyObjects и 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запрос (хотя он выглядит невероятно некорректным и уродливым, но в моем случае это работает, и я не нашел ничего лучшего во время поиска в Google) и проверьте, будет ли веб-служба отправлять статус перенаправления в качестве ответа:

// 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);

Сейчасчто этот метод делает: он принимает BindingProvider.ENDPOINT_ACCESS_PROPERTY из retrieveMyObjectsPort, то есть URL-адрес, на который этот метод порта будет отправлять запросы SOAP и отправляет простой запрос HTTP POST, как описано выше.Затем он проверяет, является ли статус ответа 307 - Temporary Redirect (также могут быть включены другие состояния, например 302 или 301), и, если это так, получает URL-адрес, на который перенаправляется веб-служба, и устанавливает новую конечную точку для указанного порта.

В моем случае этот checkRedirect метод вызывается один раз для каждого интерфейса порта веб-службы, а затем, кажется, все работает нормально:

  1. Перенаправление проверяется по URL, как http://example.com:50678/restOfUrl
  2. Веб-служба перенаправляет на URL, как https://example.com:43578/restOfUrl (обратите внимание, что аутентификация клиента веб-службы присутствует) - конечная точка порта установлена ​​на этот URL
  3. Следующие запросы веб-службы, выполненные через этот порт, будут успешными

Отказ от ответственности: я довольно новичок в веб-сервисах, и это то, чего мне удалось достичь из-за отсутствия решений для этих вопросов, поэтому, пожалуйста, исправьте меня, если что-то здесь не так.

Надеюсь, этопомогает

...