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

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

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

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

вместо

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

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

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

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


person Vinnie    schedule 27.01.2010    source источник
comment
Вы пытались использовать атрибут wsdlLocation в аннотации @WebService? Возможно, вы можете указать WSDL для возврата клиенту.   -  person ewernli    schedule 27.01.2010
comment
CXF имеет функцию специально для этого.   -  person bmargulies    schedule 27.01.2010
comment
@ewernli - Спасибо, но контейнер (Glassfish) по-прежнему перезаписывает адрес конечной точки. Кажется, это не работает.   -  person Vinnie    schedule 28.01.2010
comment
@bmargulies - CXF выглядит круто, но я не думаю, что сейчас мы сможем интегрировать эту структуру. Тем не менее, спасибо, я определенно хочу вернуться и посмотреть на это более подробно.   -  person Vinnie    schedule 28.01.2010


Ответы (4)


Я использовал фильтр и вот что у меня получилось. Кажется, это работает.

Я включил код для моего метода 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);
    }
}
person Vinnie    schedule 29.01.2010
comment
Спасибо за это. Единственная дополнительная вещь, которую мне нужно было сделать, это вызвать response.resetBuffer(); перед записью в выходной поток ответа. В противном случае будут возвращены как прежние, так и измененные полезные данные ответа. - person helvete; 28.01.2021

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

person Chris K    schedule 28.01.2010

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

В документе glassfish о реестре веб-служб говорится :

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

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

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

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

person ewernli    schedule 28.01.2010

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

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

person MikeThomas    schedule 20.03.2014