Подтвердить что ты не робот

Проблема с GWT за обратным прокси - либо nginx, либо apache

У меня проблема с GWT, когда она находится за обратным прокси. Бэкэнд-приложение развернуто в контексте - позвоните ему/контексту.

Приложение 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 не получает слово, что ему нужно добавить /context/hen искать C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc, но только тогда, когда запрос поступает через прокси-сервер. Обходным путем является добавление контекста к URL-адресу веб-сайта:

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

но это означает, что контекст теперь является частью URL-адреса, который пользователь видит, и что уродливо.

Кто-нибудь знает, как сделать GWT счастливым в этом случае?

Версия программного обеспечения:
GWT - 1.7.0 (такая же проблема с 1.7.1)
Jetty - 6.1.21 (но та же проблема существовала и при tomcat)
nginx - 0.7.62 (такая же проблема при apache 2.x)

Я просмотрел трафик между прокси и бэкэнд, используя DonsProxy, но там ничего не примечательно.

4b9b3361

Ответ 1

Я уверен, что правильный ответ здесь - исправить источник и отправить отчет об ошибке. Другой вариант - запустить приложение GWT с / на вашем сервере.

Я бы предпочел первый, но последний тоже должен работать. Если вам действительно нужны вещи, разделенные на несколько контекстов, используйте другой номер порта?

Ответ 2

У меня такая же проблема, и я открыл отчет об ошибке:

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

Проблема в том, что она была отмечена как "Дизайн", поэтому я не думаю, что она будет исправлена.

Я нашел это решение для меня. Я расширил класс 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;
      }
}

Ответ 3

Мишель,

Благодарим вас за пример сервлета для решения этой проблемы. Однако, когда я пытался использовать ваш подход, он работал в обратной прокси-среде, но не в моей среде eclipse в режиме dev.

Я сделал подход, который позволил бы мне легко перемещаться между средами dev и prod.

Как и я, я перезаписал 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, который является тем подходом, который я всегда делал.

Комментарии к этому подходу оценены

Ответ 4

У меня возникла аналогичная проблема, успешным решением было сделать все сериализованные объекты реализованным интерфейсом GWT IsSerializable (в дополнение к стандартному интерфейсу Serializable). Если вы прочтете сообщение, в нем говорится, что "будет использоваться политик последовательной версии 1.3.3, совместимый с сериализацией". 1.3.3 совместимая политика требует, чтобы все ваши сериализованные объекты реализовали интерфейс IsSerializable, поэтому, добавив его, все сработало.

У меня есть опасения, что прежняя политика будет описана в будущих версиях GWT, поэтому я также ищу лучший способ обхода.

Ответ 5

Ответ 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 Следовательно, модульBaseURL = moduleBaseURLHdr.replace( "foo/bar", "bar" ); делает GWT счастливым. Аналогично, если приложение находится в http://server/bar, а прокси-сервер работает в http://proxy/, вам нужно добавить bar к модулюBaseURL (прямо перед именем пакета). Это можно обобщить с помощью getServletContext(). GetContextPath() и т.д.

Ответ 6

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

Ответ 7

Используйте надежный JSON для вызовов RPC вместо GWT-RPC. Это решает проблему обратного прокси-сервера, поскольку файлы сериализации не требуются.