Могу ли я перехватывать вызовы для моего WSDL на Glassfish (или на любом сервере приложений)?
Я создал веб-сервис Java, используя @WebService
аннотировать и развернуть службу на сервере Glassfish, который находится за прокси-сервером.
Проблема в том, что когда кто-то обращается к нашему WSDL и смотрит на местоположение адреса конечной точки службы, которое он видит
http://app server url/service...
вместо
http://proxy server url/service...
Я хотел бы, чтобы URL-адрес прокси-сервера возвращался в расположении адреса конечной точки службы WSDL вместо URL-адреса сервера приложений.
Мне интересно, могу ли я написать фильтр или прослушиватель для прослушивания запросов к WSDL, а затем изменить адрес конечной точки службы WSDL с помощью URL-адреса прокси-сервера? Каков может быть рекомендуемый способ сделать это - я думал, что Фильтр - лучший выбор, но не был уверен на 100%?
Кстати, я думал, что в Glassfish может быть простая настройка для этого, но я не смог найти тот, который работает.
4 ответа
Я выбрал подход фильтра и вот что я придумал. Вроде работает.
Я включил код для моего Filter
"s doFilter
метод. Я тоже написал кастом HttpServletResponseWrapper
, но эта реализация была довольно простой.
обратный прокси-сервер Apache добавляет x-forwarded-host
значение для заголовка HTTP (и это имя, которое я использую для замены имени сервера приложений). Еще одна альтернатива, о которой я подумал, - разместить адрес прокси-сервера в качестве свойства на сервере приложений и получить его. В конечном счете, я думал, что это был более чистый путь.
/*
* Replace the server URL with the proxy server URL when called from a proxy server
*/
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain filterChain) throws IOException, ServletException
{
WsdlResponseWrapper myResponse = new WsdlResponseWrapper((HttpServletResponse) response);
filterChain.doFilter(request, myResponse);
boolean isResponseOutputStream = myResponse.getOutputStreamContent().length > 0;
/*
* The servlet response sent into this method only allows access to
* getOutputStream or getWriter, not both. It will throw an
* exception if an attempt is made to to access both.
*
* If this reason, I'm checking the output stream first and writing
* that content if it exists, then printing to the writer only if
* the output stream is empty.
*/
StringBuffer responseBuffer;
if (isResponseOutputStream) {
responseBuffer = new StringBuffer(new String(myResponse.getOutputStreamContent()));
} else {
responseBuffer = new StringBuffer(myResponse.getWriterContent());
}
// Change the URL when called from a proxy server
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String requestedHostname = httpServletRequest.getHeader("x-forwarded-host");
if ((null != requestedHostname) && !requestedHostname.isEmpty()) {
String myHostname = httpServletRequest.getHeader("host");
int myPort = httpServletRequest.getLocalPort();
// change the hostname
int index = responseBuffer.indexOf(myHostname);
int length = myHostname.length();
while (index > -1) {
responseBuffer.replace(index, index+length, requestedHostname);
index = responseBuffer.indexOf(myHostname);
}
// remove the port
String portString = ":" + myPort;
length = portString.length();
index = responseBuffer.indexOf(portString);
while (index > -1) {
responseBuffer.replace(index, index+length, "");
index = responseBuffer.indexOf(portString);
}
}
}
// forward the response
if (isResponseOutputStream) {
response.getOutputStream().write(responseBuffer.toString().getBytes());
} else {
response.getWriter().print(responseBuffer);
}
}
Из статьи Javaboutique о сервлет-фильтрах
public final class TimerFilter implements Filter
{
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException
{
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long stopTime = System.currentTimeMillis();
System.out.println("Time to execute request: " + (stopTime - startTime) +
" milliseconds");
}
...
вызов chain.doFilter вызовет обычный сервлет в вашем случае (я предполагаю, что @WebService предоставляется через API сервлета), и вы можете затем прочитать результат из исходного веб-сервиса, изменить его и передать обратно вашему собственному клиенту.
Рассматривали ли вы использование реестра веб-службы для этого?
Документ Glassfish о реестре веб-службы гласит:
Если вы используете балансировщик нагрузки, введите имя хоста балансировщика нагрузки, номер порта и номер порта SSL. Если вы публикуете веб-службу во внешнем реестре, где WSDL можно найти через Интернет, эти параметры заменят имя хоста и имя порта, указанные в WSDL, на балансировщик нагрузки.
Так что это должно работать и для вашего прокси.
Вот два ресурса, которые могут быть интересны: страница управления glassfish ws, статья о том, как настроить реестр.
Я никогда не использовал реестр самостоятельно, и согласен с тем, что он немного тяжеловесен для того, чего вы хотите достичь, но, похоже, это возможный способ публикации информации о конечных точках веб-службы для потребителей.
Если Apache - ваш прокси, вы можете попробовать сделать то, что я сделал, что действительно просто. Apache вызывает проблему (вроде как), поэтому используйте Apache, чтобы исправить ее: