Могу ли я перехватывать вызовы для моего WSDL на Glassfish (или на любом сервере приложений)? - PullRequest
3 голосов
/ 27 января 2010

Я создал веб-сервис Java с помощью аннотации @WebService и развернул сервис на сервере Glassfish, который находится за прокси-сервером.

Проблема в том, что когда кто-то обращается к нашему WSDL и смотрит на местоположение адреса конечной точки службы, которое он видит

http://app server url/service...

вместо

http://proxy server url/service...

Мне бы хотелось, чтобы URL-адрес прокси-сервера возвращался в расположении адреса конечной точки службы WSDL вместо URL-адреса сервера приложений.

Что мне интересно, могу ли я написать фильтр или прослушиватель для прослушивания запросов к WSDL, а затем изменить адрес конечной точки службы WSDL с помощью URL-адреса прокси-сервера? Каков может быть рекомендуемый способ сделать это - я думал, что Фильтр - лучший выбор, но не был уверен на 100%?

Кстати, я думал, что в Glassfish может быть простая настройка, но Мне не удалось найти такую, которая работает .

Ответы [ 4 ]

2 голосов
/ 29 января 2010

Я выбрал подход фильтра и вот что я придумал. Вроде работает.

Я включил код для моего Filter 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);
    }
}
1 голос
/ 28 января 2010

Рассматривали ли вы использование реестра веб-службы для этого?

Документ glassfish о реестре веб-службы гласит:

Если вы используете балансировщик нагрузки, введите имя хоста балансировщика нагрузки, номер порта и номер порта SSL. Если вы публикуете веб-сервис во внешний реестр, где WSDL можно найти через Интернет, эти варианты заменят имя хоста и имя порта, указанные в WSDL к одному из нагрузки балансир.

Так что это должно работать и для вашего прокси.

Вот два ресурса, которые могут быть интересны: glassfish ws management , статья о том, как настроить реестр .

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

1 голос
/ 28 января 2010

С 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 сервлета), и вы можете затем прочитать результат из исходного веб-сервиса, изменить его и передать его обратно своему клиенту.

0 голосов
/ 21 марта 2014

Если Apache - ваш прокси, вы можете попробовать сделать то, что я сделал, что действительно просто. Apache вызывает проблему (вроде как), поэтому используйте Apache, чтобы исправить ее:

https://stackoverflow.com/a/18136594/2666055

...