3

我使用@WebService注释创建了一个 Java Web 服务,并将该服务部署到位于代理服务器后面的 Glassfish 服务器。

问题是当有人访问我们的 WSDL 并查看他们看到的服务端点地址位置时

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

代替

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

我希望在 WSDL 的服务端点地址位置而不是应用服务器 url 中返回代理服务器 URL。

我想知道的是,我是否可以编写一个过滤器或侦听器来监听对 WSDL 的请求,然后用代理服务器 URL 修改 WSDL 服务端点地址?推荐的方法是什么 - 我认为过滤器是最好的选择,但不是 100% 确定?

顺便说一句 - 我认为 Glassfish 中可能有一个简单的设置来执行此操作,但我无法找到一个有效的设置

4

4 回答 4

3

我采用了过滤方法,这就是我想出的。它似乎工作。

我已经包含了我FilterdoFilter方法的代码。我还写了一个 custom 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);
    }
}
于 2010-01-29T19:22:07.797 回答
1

来自关于 servlet-filters 的 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 的调用将调用普通的servlet(我假设@WebService 是通过servlet API 提供的),然后您可以从原始Web 服务中读取结果,对其进行修改并将其传回给你自己的客户。

于 2010-01-28T02:37:23.343 回答
1

您是否考虑过为此使用Web 服务注册表

关于 Web 服务注册表的glassfish文档说:

如果您使用负载均衡器,请输入负载均衡器主机名、端口号和 SSL 端口号。如果您将 Web 服务发布到外部注册表,其中 WSDL 可以通过 Internet 找到,这些选项会将 WSDL 中指定的主机名和端口名替换为负载均衡器之一。

所以这也适用于您的代理。

这里有两个可能有趣的资源:glassfish ws 管理页面,一篇关于如何设置注册表的文章。

我自己从未使用过注册表,并且同意它对于您想要实现的目标有点重,但它似乎是为消费者发布 Web 服务端点信息的一种可能方式。

于 2010-01-28T11:15:43.980 回答
0

如果 Apache 是你的代理,你可以试试我做的,这很简单。Apache 导致问题(排序),所以使用 Apache 来修复它:

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

于 2014-03-20T22:00:34.363 回答