2009-10-04 29 views
16

Tôi gặp sự cố này với GWT khi nó nằm sau proxy ngược. Ứng dụng phụ trợ được triển khai trong một ngữ cảnh - hãy gọi nó/ngữ cảnh.Vấn đề với GWT đằng sau proxy ngược - hoặc nginx hoặc apache

Ứng dụng GWT hoạt động tốt khi tôi nhấn nó trực tiếp:

http://host:8080/context/

tôi có thể cấu hình một proxy ngược trước mặt nó nó. Dưới đây là ví dụ nginx tôi:

 
upstream backend { 
    server 127.0.0.1:8080; 
} 

... 

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

Tuy nhiên, khi tôi chạy qua proxy ngược, GWT bị nhầm lẫn, nói:

 
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. 

Nói cách khác, GWT không nhận được từ đó nó cần phải prepend/context/hen tìm C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc, nhưng chỉ khi yêu cầu đến proxy. Giải pháp là thêm ngữ cảnh vào url cho trang web:

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

nhưng điều đó có nghĩa là ngữ cảnh hiện là một phần của url mà người dùng nhìn thấy và điều đó thật xấu.

Bất kỳ ai biết cách làm cho GWT hài lòng trong trường hợp này?

phiên bản phần mềm:
GWT - 1.7.0 (cùng một vấn đề với 1.7.1)
Jetty - 6.1.21 (nhưng cùng một vấn đề tồn tại dưới tomcat)
nginx - 0.7.62 (cùng một vấn đề dưới apache 2.x)

Tôi đã xem lưu lượng truy cập giữa proxy và phần phụ trợ bằng cách sử dụng DonsProxy, nhưng không có gì đáng chú ý ở đó.

Trả lời

3

Tôi khá chắc chắn câu trả lời đúng ở đây là vá nguồn và gửi báo cáo lỗi. Một tùy chọn khác là chạy ứng dụng GWT tại / trên chương trình phụ trợ của bạn.

Tôi thích cái cũ hơn, nhưng cái sau cũng nên hoạt động. Nếu bạn thực sự cần những thứ tách ra thành nhiều bối cảnh, sử dụng một số cổng khác nhau?

+0

Tôi không nhất thiết cần những thứ được tách ra trong thời gian ngắn - nhưng trình tạo ứng dụng đặt mô-đun theo ngữ cảnh theo mặc định và tôi có thể muốn phân tách các phần nhất định thành các mô-đun khác. Vá mã nguồn (tới GWT) có vẻ giống như câu trả lời đúng, vì dường như mọi thứ đều được định cấu hình chính xác. –

+1

Cách tôi nhìn thấy nó, bạn đã có một vấn đề lộn xộn, và những người khác có thể được hưởng lợi từ việc sửa chữa của bạn, do đó, một bản vá sẽ cực kỳ có giá trị. Nếu bạn đi tuyến đường này, hãy chắc chắn để đưa tập tin bản vá của bạn lên trên Gist (http://gist.github.com/) hoặc tương tự, và liên kết câu hỏi này với nó, trong trường hợp các bản vá không được chấp nhận ngay lập tức. –

2

Tôi đã gặp phải sự cố tương tự, giải pháp thành công là làm cho tất cả các đối tượng được tuần tự hóa triển khai giao diện IsSerializable của GWT (ngoài giao diện Serializable chuẩn). Nếu bạn đọc thông báo, nó nói rằng 'một chính sách tuần tự tương thích 1.3.3 kế thừa sẽ được sử dụng' - chính sách tương thích 1.3.3 yêu cầu tất cả các đối tượng tuần tự của bạn thực hiện giao diện IsSerializable, do đó, bằng cách thêm nó, mọi thứ đã hoạt động.

Tôi lo ngại rằng chính sách cũ sẽ không được hỗ trợ trong các phiên bản GWT trong tương lai, vì vậy tôi cũng đang tìm kiếm giải pháp tốt hơn cho bản thân.

+0

Thú vị. Kết nối giữa giao diện IsSerializable và proxy ngược lại là gì? –

+0

Với ví dụ của bạn, proxy ngược đang gây ra tệp chính sách tuần tự hóa (C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc) không tìm thấy. Bởi vì điều này, nó quay trở lại 1.3.3 chính sách tuần tự tương thích, không yêu cầu tệp chính sách như vậy, nhưng thay vào đó yêu cầu các đối tượng được tuần tự hóa để triển khai giao diện IsSerializable – Chi

+1

Tôi đồng ý rằng có một số thứ mà proxy đang thực hiện. Tôi nghĩ rằng nó không có gì để làm với những gì các giao diện java được sử dụng. Câu hỏi đặt ra là, proxy làm gì gây nhầm lẫn cho GWT? Các tiêu đề trông giống nhau, các URL đang được dịch chính xác, v.v. Yêu cầu cho tệp C7F% ... không bao giờ thực sự đi qua proxy, vì tất cả được xử lý ở phía máy chủ, dựa trên những gì tôi thấy trên dây có cả và không có proxy. –

8

Tôi có cùng một vấn đề, và tôi mở một báo cáo lỗi:

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

Vấn đề là nó được đánh dấu "Khi thiết kế", vì vậy tôi không nghĩ rằng nó sẽ được cố định.

Tôi đã tìm thấy giải pháp này cho tôi. Tôi đã mở rộng lớp RemoteServiceServlet và tôi buộc GWT tải tệp chính sách tuần tự hóa bắt đầu từ ContextName thay vì URL. Sau đó, tôi mở rộng dịch vụ lớp của tôi thay vì lớp RemoteServiceServlet. Bằng cách này, ứng dụng sẽ được hủy liên kết khỏi url từ nơi nó sẽ được gọi.

Ở đây có lớp tùy chỉnh của tôi:

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

Tôi thích giải pháp này, nhưng giống như KC Berg, nó chỉ hoạt động trong môi trường sản xuất. Giải pháp cuối cùng của tôi, được đặt tại http://gist.github.com/476175, sử dụng mã này nhưng cố gắng tải tệp thông thường trước khi gọi 'loadSerializationPolicy()'. –

7

Michele,

Cảm ơn bạn đã dụ servlet để xử lý vấn đề này. Tuy nhiên khi tôi đã cố gắng sử dụng cách tiếp cận của bạn nó làm việc trong môi trường proxy ngược lại nhưng không phải trong môi trường eclipse chế độ dev của tôi.

Tôi đã thực hiện một cách tiếp cận cho phép tôi liên tục di chuyển giữa các môi trường dev và prod của mình.

Như bạn đã làm tôi ghi đè lên RemoteServiceServlet nhưng tôi chỉ thay thế sau ...

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

Trong cấu hình apache tôi thêm ...

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

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

Phê duyệt này h hoạt động trong tất cả các tình huống và ủy nhiệm url "mucking" đến các thiết lập proxy của apache, đó là phương pháp mà tôi luôn thực hiện.

Nhận xét về cách tiếp cận này được đánh giá cao

+0

vui lòng, bạn có thể đăng toàn bộ cấu hình Apache không? Tôi đang cố gắng nhưng không hoạt động và có thể tôi đang thiếu thứ gì đó. –

+1

giải pháp rất thanh lịch và tốt đẹp, tôi xác nhận phương pháp này cũng hoạt động trong gft 2.6.0, +1 từ tôi. –

2

Câu trả lời của KC là tốt. Đối với những người không muốn muck xung quanh với cấu hình apache, hoặc cần một cách nhanh chóng và bẩn để kiểm tra, đây là một giải pháp duy nhất mã.

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

Ứng dụng này trên http://server/bar, proxy đang phục vụ nó ở http://proxy/foo/bar Do đó moduleBaseURL = moduleBaseURLHdr.replace ("foo/bar", "bar"); làm cho GWT hạnh phúc. Tương tự, nếu ứng dụng ở số http://server/bar và proxy đang phục vụ tại http://proxy/, bạn cần thêm thanh vào moduleBaseURL (ngay trước tên gói). Điều này có thể được khái quát hóa thông qua việc sử dụng getServletContext(). GetContextPath() v.v.

+0

Đẹp. Bạn có nhớ lại phiên bản GWT nào đã hoạt động không? (Câu hỏi năm 2009 vẫn có thể áp dụng ngày nay, hoặc có thể không, nhưng tôi cho rằng bạn đã sử dụng phiên bản mới hơn?) – Arjan

+0

Nó hoạt động cho GWT 2.3 –

0

Sử dụng JSON yên tĩnh cho các cuộc gọi RPC thay vì GWT-RPC. Điều này giải quyết vấn đề đảo ngược proxy vì không có tệp tuần tự được yêu cầu.

1

Mục tiêu của tôi là tránh (các) tiêu đề bổ sung giúp triển khai và cấu hình khó hơn. Tôi giải quyết vấn đề này bằng cách ghi đè 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); 
    } 

Trong đoạn code trên:
extractGwtModuleName() chiết xuất chuỗi cuối cùng tiền tố và/hoặc sau dấu gạch chéo
joinPaths() tham gia nhiều phần url, loại bỏ dấu gạch chéo không cần thiết

Các vấn đề liên quan