2009-10-04 2 views
16

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

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

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

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

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

Software версии:
GWT - 1.7.0 (та же проблема с 1.7.1)
Jetty - 6.1.21 (но та же проблема существовала под котом)
Nginx - 0.7.62 (та же проблема при апача 2.x)

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

ответ

3

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

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

+0

В краткосрочной перспективе мне не обязательно нужны вещи, но разработчик приложений устанавливает по умолчанию модули с контекстом, и я могу выделить отдельные части в других модулях. Исправление источника (до GWT) звучит как правильный ответ, так как кажется, что все настроено правильно. –

+1

Как я вижу это, у вас есть грязная проблема, и другие люди, вероятно, выиграют от вашего исправления, поэтому патч будет чрезвычайно ценным. Если вы идете по этому маршруту, обязательно разместите файл исправлений на Gist (http://gist.github.com/) или аналогичный, и связать этот вопрос с ним, если патч не будет принят немедленно. –

2

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

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

+0

Интересно. Какая связь между интерфейсом IsSerializable и обратным прокси-сервером? –

+0

В вашем примере обратный прокси вызывает файл политики сериализации (C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc), чтобы его не найти. Из-за этого он возвращается к 1.3.3 совместимая политика сериализации, которая не требует такого файла политики, но вместо этого требует сериализованных объектов для реализации интерфейса IsSerializable – Chi

+1

Я согласен, что есть что-то, что делает прокси-сервер. Я думаю, что это не имеет никакого отношения к тому, что использует интерфейсы java. Вопрос в том, что делает прокси-сервер, запутывающий GWT? Заголовки выглядят одинаково, URL-адреса переводятся правильно и т. Д. Запрос на файл C7F% ... никогда не проходит через прокси-сервер, поскольку он обрабатывается на стороне сервера, основываясь на том, что я вижу на проводнике как с прокси-сервером, так и без него. –

8

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

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

Проблема заключается в том, что он был отмечен «Как 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; 
     } 
} 
+0

Мне нравится это решение, но, как и KC Berg, он работает только в производственной среде. Мое окончательное решение, расположенное по адресу http://gist.github.com/476175, использует этот код, но пытается нормально загрузить файл перед вызовом 'loadSerializationPolicy()'. –

7

Мишель,

Спасибо за пример сервлета справиться с этой проблемой. Однако, когда я пытался использовать ваш подход, он работал в обратной прокси-среде, но не в моей среде 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); 
} 

В моей апача конфигурации я добавил ...

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

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

Этот подход h работает во всех сценариях и делегирует URL-адрес «mucking» к настройкам прокси-сервера apache, который является подходом, который я всегда применял.

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

+0

, пожалуйста, можете ли вы опубликовать всю конфигурацию Apache? Я пытаюсь это сделать, но не работает, и, может быть, я что-то пропустил. – 2011-03-11 14:31:24

+1

очень элегантное и приятное решение, я подтверждаю, что этот подход работает и в gwt 2.6.0, +1 от меня. –

2

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

+0

Ницца. Вы помните, для какой версии GWT это сработало? (Вопрос 2009 года может по-прежнему применяться в настоящее время или, может быть, нет, но я предполагаю, что вы использовали более новую версию?) – Arjan

+0

Он работал для GWT 2.3 –

0

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

1

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

Смежные вопросы