2009-10-04 18 views
16

Estoy teniendo este problema con GWT cuando está detrás de un proxy inverso. La aplicación de back-end se implementa dentro de un contexto, vamos a llamarlo/contexto.Problema con GWT detrás de un proxy inverso, ya sea nginx o apache

La aplicación GWT funciona bien cuando golpeo directamente:

http://host:8080/context/

puedo configurar un proxy inverso frente a ella misma. Aquí está mi ejemplo nginx:

 
upstream backend { 
    server 127.0.0.1:8080; 
} 

... 

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

Pero, cuando corro a través del proxy inverso, GWT se confunde, diciendo:

 
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. 

En otras palabras, GWT no está recibiendo la palabra que necesita prepend/context/hen busca C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc, pero solo cuando la solicitud viene a través del proxy. Una solución es agregar el contexto de la URL del sitio web:

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

pero eso significa que el contexto es ahora parte de la URL que el usuario ve, y eso es feo.

¿Alguien sabe cómo hacer feliz a GWT en este caso?

versiones de software:
GWT - 1.7.0 (mismo problema con 1.7.1)
Jetty - 6.1.21 (pero el mismo problema existía bajo Tomcat)
nginx - 0.7.62 (mismo problema bajo Apache 2.x)

He visto el tráfico entre el proxy y el backend usando DonsProxy, pero no hay nada digno de mención allí.

Respuesta

3

Estoy bastante seguro de que la respuesta correcta aquí es corregir el código fuente y enviar un informe de error. Otra opción sería ejecutar la aplicación GWT al / en su back-end.

Preferiría la primera, pero la última debería funcionar también. Si realmente necesita cosas separadas en múltiples contextos, use un número de puerto diferente?

+0

No necesito necesariamente separar cosas en el corto plazo, pero el creador de aplicaciones establece los módulos con un contexto de forma predeterminada, y es posible que desee separar ciertas piezas en otros módulos. El parche de la fuente (a GWT) suena como la respuesta correcta, ya que parece que todo está configurado correctamente. –

+1

De la forma en que lo veo, tienes un problema complicado, y es probable que otras personas se beneficien de tu solución, por lo que un parche sería extremadamente valioso. Si sigue esta ruta, asegúrese de poner su archivo de parche en Gist (http://gist.github.com/) o similar, y vincule esta pregunta, en caso de que no se acepte el parche inmediatamente. –

2

Me encontré con un problema similar, una solución exitosa fue hacer que todos los objetos serializados implementaran la interfaz IsSerializable de GWT (además de la interfaz Serializable estándar). Si lee el mensaje, indica que 'se usará una política de serialización heredada, 1.3.3 compatible' - la política compatible con 1.3.3 requiere que todos sus objetos serializados implementen la interfaz IsSerializable, por lo que al agregarla, todo funcionó.

Me preocupa que la política heredada se respaldará en futuras versiones de GWT, por lo que también estoy buscando una mejor solución.

+0

interesante. ¿Cuál es la conexión entre la interfaz IsSerializable y el proxy inverso? –

+0

Con su ejemplo, el proxy inverso está causando que el archivo de política de serialización (C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc) no se encuentre. Debido a esto, está volviendo al 1.3.3 política de serialización compatible, que no requiere dicho archivo de política, sino que requiere objetos serializados para implementar la interfaz IsSerializable – Chi

+1

Estoy de acuerdo en que hay algo que el proxy está haciendo. Creo que no tiene nada que ver con las interfaces java que están en uso. La pregunta es, ¿qué está haciendo el proxy que confunde a GWT? Los encabezados tienen el mismo aspecto, las URL se traducen correctamente, y así sucesivamente. La solicitud del archivo C7F% ... en realidad nunca pasa por el proxy, ya que todo se maneja en el lado del servidor, en base a lo que veo en el cable con y sin el proxy. –

8

que tienen el mismo problema, y ​​yo abrimos un informe de error:

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

El problema es que se ha marcado "como el diseño", así que no creo que se fijará.

Encontré esta solución para mí. Extendí la clase RemoteServiceServlet y obligué a GWT a cargar el archivo de políticas de serialización a partir de ContextName en lugar de URL. Luego extendí mi servicio a mi clase en lugar de la clase RemoteServiceServlet. De esta forma, la aplicación se desvinculará de la url desde donde se llamará.

Aquí no es mi clase personalizada:

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; 
     } 
} 
+0

Me gusta esta solución, pero al igual que KC Berg, solo funciona en el entorno de producción. Mi solución final, ubicada en http://gist.github.com/476175, usa este código pero intenta cargar el archivo normalmente antes de llamar a 'loadSerializationPolicy()'. –

7

Michele,

Gracias por el ejemplo de servlet para manejar este problema. Sin embargo, cuando traté de utilizar su enfoque funcionó en el entorno de proxy inverso, pero no en mi entorno eclipse del modo dev.

Tomé un enfoque que me permitiría moverme sin problemas entre mis entornos de desarrollo y producción.

Al igual que hizo que sobreescribí RemoteServiceServlet pero sólo sustituye siguiente ...

@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); 
} 

En mi configuración de Apache añadí ...

ProxyPass /app/ ajp://localhost:8009/App-0.0.1-SNAPSHOT/ 

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

Esta aprobación h funciona en todos los escenarios y delega el url "mucking" a la configuración proxy de apache, que es el enfoque que siempre he adoptado.

Se agradecen los comentarios sobre este enfoque

+0

por favor, ¿puedes publicar toda la configuración de Apache? Lo estoy intentando pero no funciona y tal vez me esté perdiendo algo. –

+1

solución muy elegante y agradable, confirmo que este enfoque también funciona en gwt 2.6.0, +1 de mí. –

2

La respuesta de KC es buena. Para aquellos que no quieren perder el tiempo con las configuraciones de Apache, o necesitan una manera rápida y sucia de probar, aquí hay una solución de solo código.

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); 
} 

La aplicación es en http://server/bar, el proxy está sirviendo al http://proxy/foo/bar Por lo tanto moduleBaseURL = moduleBaseURLHdr.replace ("foo/bar", "bar"); hace feliz a GWT Del mismo modo, si la aplicación está en http://server/bar y el servidor proxy se encuentra en el http://proxy/, debe agregar una barra al módulo BaseURL (justo antes del nombre del paquete). Esto se puede generalizar mediante el uso de getServletContext(). GetContextPath() etc ...

+0

Agradable. ¿Recuerdas para qué versión de GWT funcionó? (La pregunta de 2009 todavía podría aplicarse hoy en día, o tal vez no, pero supongo que utilizó una versión más reciente?) – Arjan

+0

Funcionó para GWT 2.3 –

0

Use restful JSON para sus llamadas RPC en lugar de GWT-RPC. Esto resuelve el problema del proxy inverso ya que no se requieren archivos de serialización.

1

Mi objetivo era evitar encabezados adicionales que dificultarían la implementación y la configuración. He resuelto este problema reemplazando 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); 
    } 

En el código anterior:
extractGwtModuleName() extractos última cadena precedido y/o seguido de barra
joinPaths() se une a varios partes del URL, elimina las barras innecesarias

Cuestiones relacionadas