Проблема с GWT за обратным прокси-сервером - nginx или apache - PullRequest
16 голосов
/ 05 октября 2009

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

Приложение 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)
Пристань - 6.1.21 (но та же проблема существовала при tomcat)
nginx - 0.7.62 (та же проблема в apache 2.x)

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

Ответы [ 7 ]

8 голосов
/ 01 мая 2010

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

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

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

Я нашел это решение для себя. Я расширил класс RemoteServiceServlet и заставил GWT загрузить файл политики сериализации, начиная с ContextName, а не URL. Затем я расширил свой сервис своим классом вместо класса RemoteServiceServlet. Таким образом, приложение будет удалено из ссылки, с которой оно будет вызываться.

Здесь есть мой пользовательский класс:

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;
      }
}
7 голосов
/ 22 сентября 2010

Michele

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

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

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

Комментарии по этому подходу приветствуются

3 голосов
/ 12 октября 2009

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

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

2 голосов
/ 28 мая 2012

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 (прямо перед именем пакета). Это можно обобщить с помощью getServletContext (). GetContextPath () и т. Д. *

2 голосов
/ 05 октября 2009

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

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

1 голос
/ 30 июля 2014

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

0 голосов
/ 03 августа 2012

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

...