首页 文章

反向代理背后的GWT问题 - 无论是nginx还是apache

提问于
浏览
16

当它在反向代理后面时,我遇到了这个问题 . 后端应用程序部署在上下文中 - 让我们称之为/上下文 .

当我直接点击它时,GWT应用程序正常工作:

http://host:8080/context/

我可以在它前面配置一个反向代理 . 这是我的nginx示例:

upstream backend {
    server 127.0.0.1:8080;
}

...

location / {
   proxy_pass        http://backend/context/;
}

但是,当我通过反向代理时,GWT感到困惑,说:

2009-10-04 14:05:41.140:/:WARN:  Login: ERROR: The serialization policy file '/C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc' was not found; did you forget to include it in this deployment?
2009-10-04 14:05:41.140:/:WARN:  Login: WARNING: Failed to get the SerializationPolicy 'C7F5ECA5E3C10B453290DE47D3BE0F0E' for module 'https://hostname:444/'; a legacy, 1.3.3 compatible, serialization policy will be used.  You may experience SerializationExceptions as a result.
2009-10-04 14:05:41.292:/:WARN:  StoryService: ERROR: The serialization policy file '/0445C2D48AEF2FB8CB70C4D4A7849D88.gwt.rpc' was not found; did you forget to include it in this deployment?
2009-10-04 14:05:41.292:/:WARN:  StoryService: WARNING: Failed to get the SerializationPolicy '0445C2D48AEF2FB8CB70C4D4A7849D88' for module 'https://hostname:444/'; a legacy, 1.3.3 compatible, serialization policy will be used.  You may experience SerializationExceptions as a result.

换句话说,GWT没有得到它需要前置/上下文/ hen寻找C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc这个词,但只有当请求来自代理时 . 解决方法是将上下文添加到网站的URL:

location /context/ {
    proxy_pass        http://backend/context/;
}

但这意味着上下文现在是用户看到的网址的一部分,而且很难看 .

有人知道如何让GWT在这种情况下开心吗?

软件版本:
GWT - 1.7.0(与1.7.1相同的问题)
Jetty - 6.1.21(但tomcat下存在同样的问题)
nginx - 0.7.62(apache 2.x下的同样问题)

我已经使用DonsProxy查看了代理和后端之间的流量,但那里没有什么值得注意的 .

7 回答

  • 2

    我很确定这里的正确答案是修补源代码并提交错误报告 . 另一种选择是在你的后端运行 / 的GWT应用程序 .

    我更喜欢前者,但后者也应该起作用 . 如果您确实需要将事物分成多个上下文,请使用不同的端口号?

  • 1

    我有同样的问题,我打开了一个错误报告:

    http://code.google.com/p/google-web-toolkit/issues/detail?id=4817

    问题是它被标记为“As Design”,所以我认为它不会被修复 .

    我找到了这个解决方案 . 我扩展了类RemoteServiceServlet,并强制GWT从ContextName而不是URL开始加载序列化策略文件 . 然后我扩展了我的服务我的类而不是RemoteServiceServlet类 . 通过这种方式,应用程序将从其将被调用的URL取消链接 .

    这里有我的自定义类:

    import java.io.IOException;
    import java.io.InputStream;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.text.ParseException;
    
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    
    import com.google.gwt.user.server.rpc.RemoteServiceServlet;
    import com.google.gwt.user.server.rpc.SerializationPolicy;
    import com.google.gwt.user.server.rpc.SerializationPolicyLoader;
    
    public class MyRemoteServiceServlet extends RemoteServiceServlet
    {
        @Override
        protected SerializationPolicy doGetSerializationPolicy(HttpServletRequest request, String moduleBaseURL, String strongName)
        {
            return MyRemoteServiceServlet.loadSerializationPolicy(this, request, moduleBaseURL, strongName);
        }
    
    
        /**
          * Used by HybridServiceServlet.
          */
          static SerializationPolicy loadSerializationPolicy(HttpServlet servlet,
          HttpServletRequest request, String moduleBaseURL, String strongName) {
        // The serialization policy path depends only by contraxt path
        String contextPath = request.getContextPath();
    
        SerializationPolicy serializationPolicy = null;
    
    
        String contextRelativePath = contextPath + "/";
    
    
    
          String serializationPolicyFilePath = SerializationPolicyLoader.getSerializationPolicyFileName(contextRelativePath
              + strongName);
    
          // Open the RPC resource file and read its contents.
          InputStream is = servlet.getServletContext().getResourceAsStream(
              serializationPolicyFilePath);
          try {
            if (is != null) {
              try {
            serializationPolicy = SerializationPolicyLoader.loadFromStream(is,
                null);
              } catch (ParseException e) {
            servlet.log("ERROR: Failed to parse the policy file '"
                + serializationPolicyFilePath + "'", e);
              } catch (IOException e) {
            servlet.log("ERROR: Could not read the policy file '"
                + serializationPolicyFilePath + "'", e);
              }
            } else {
              String message = "ERROR: The serialization policy file '"
              + serializationPolicyFilePath
              + "' was not found; did you forget to include it in this deployment?";
              servlet.log(message);
            }
          } finally {
            if (is != null) {
              try {
            is.close();
              } catch (IOException e) {
            // Ignore this error
              }
            }
          }
    
        return serializationPolicy;
          }
    }
    
  • 8

    米歇尔,

    感谢您使用示例servlet来处理此问题 . 但是,当我尝试使用您的方法时,它在反向代理环境中工作,但不在我的开发模式eclipse环境中 .

    我采取了一种方法,可以让我在开发和 生产环境 环境之间无缝移动 .

    正如你所做的那样,我覆盖了RemoteServiceServlet,但我只更换了以下内容......

    @Override
    protected SerializationPolicy doGetSerializationPolicy(
            HttpServletRequest request, String moduleBaseURL, String strongName) {
        //get the base url from the header instead of the body this way 
        //apache reverse proxy with rewrite on the header can work
        String moduleBaseURLHdr = request.getHeader("X-GWT-Module-Base");
    
        if(moduleBaseURLHdr != null){
            moduleBaseURL = moduleBaseURLHdr;
        }
    
        return super.doGetSerializationPolicy(request, moduleBaseURL, strongName);
    }
    

    在我的apache配置中,我添加了...

    ProxyPass /app/ ajp://localhost:8009/App-0.0.1-SNAPSHOT/
    
    RequestHeader edit X-GWT-Module-Base ^(.*)/app/(.*)$ $1/App-0.0.1-SNAPSHOT/$2
    

    这种方法适用于所有场景,并将url“mucking”委托给apache的代理设置,这是我一直采用的方法 .

    对此方法的评论表示赞赏

  • 7

    我遇到了类似的问题,一个成功的解决方法是让所有序列化对象实现GWT的IsSerializable接口(除了标准的Serializable接口) . 如果您阅读该消息,它会声明“将使用遗留的,1.3.3兼容的序列化策略” - 1.3.3兼容策略要求所有序列化对象都实现IsSerializable接口,因此通过添加它,一切正常 .

    我确实担心在未来的GWT版本中将不支持遗留策略,因此我也在寻找更好的解决方法 .

  • 0

    KC的答案很好 . 对于那些不想使用apache配置,或者需要快速而肮脏的测试方法的人来说,这里只是一个代码解决方案 .

    protected SerializationPolicy doGetSerializationPolicy(final HttpServletRequest request, String moduleBaseURL, final String strongName) {
        final String moduleBaseURLHdr = request.getHeader("X-GWT-Module-Base");
        if (moduleBaseURLHdr != null) {
            moduleBaseURL = moduleBaseURLHdr.replace("foo/bar", "bar");
        }
        return super.doGetSerializationPolicy(request, moduleBaseURL, strongName);
    }
    

    该应用程序在 http://server/bar 上,代理服务于 http://proxy/foo/bar 因此,moduleBaseURL = moduleBaseURLHdr.replace("foo/bar","bar");使GWT感到高兴 . 同样,如果应用程序位于 http://server/bar 且代理服务于 http://proxy/ ,则需要向moduleBaseURL添加bar(位于包名称之前) . 这可以通过使用getServletContext() . getContextPath()等来推广......

  • 2

    我的目标是避免额外的 Headers ,这将使部署和配置更难 . 我通过覆盖 RemoteServiceServlet.doGetSerializationPolicy() 解决了这个问题:

    @Override
        protected SerializationPolicy doGetSerializationPolicy(HttpServletRequest request, String moduleBaseURL, String strongName) {
            String localServerAddress = "http://127.0.0.1:" + getThreadLocalRequest().getLocalPort();
            String localContextPath = getServletConfig().getServletContext().getContextPath();
            String moduleName = extractGwtModuleName(moduleBaseURL); 
            String localModuleBaseURL = joinPaths(localServerAddress, localContextPath, moduleName, "/"); 
            return super.doGetSerializationPolicy(request, localModuleBaseURL, strongName);
        }
    

    在上面的代码中:
    extractGwtModuleName() 提取前缀为和/或后跟斜杠的最后一个字符串
    joinPaths() 连接多个url部分,删除不必要的斜杠

  • 3

    为您的RPC调用而不是GWT-RPC使用restful JSON . 这解决了反向代理问题,因为不需要序列化文件 .

相关问题