Столкнулся с той же проблемой около месяца назад.
Классы клиентов веб-службы были созданы с использованием 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
метод вызывается один раз для каждого интерфейса порта веб-службы, а затем, кажется, все работает нормально:
- Перенаправление проверяется по URL, как
http://example.com:50678/restOfUrl
- Веб-служба перенаправляет на URL, как
https://example.com:43578/restOfUrl
(обратите внимание, что аутентификация клиента веб-службы присутствует) - конечная точка порта установлена на этот URL - Следующие запросы веб-службы, выполненные через этот порт, будут успешными
Отказ от ответственности: я довольно новичок в веб-сервисах, и это то, чего мне удалось достичь из-за отсутствия решений для этих вопросов, поэтому, пожалуйста, исправьте меня, если что-то здесь не так.
Надеюсь, этопомогает