One of the problems with using GWT is that when you run in devmode, GWT manages its own instance of a Jetty server (I think it’s a Jetty server anyway). Unless you want to use GWT’s own server implementation, and perhaps even run in on Google AppEngine, you’re going to run into the same origin policy. In order to get around this problem, you have to set up a proxy server of some sort. I found a bit of servlet code written by Stou Sandalski which allows you to do this, made to solve the exact same problem in fact. However, I wanted a proxy which would not only support GET and POST requests, but basically allow me to do whatever I wanted. I also wanted it to send all request headers across to the target server. The only dependency is Apache HttpCore and HttpClient.

  1. package com.package.server;
  2.  
  3. /**
  4.  * Copyright 2010 Kenneth Jorgensen (kennethjorgensen.com) (modifications)
  5.  * - original code can be found at http://www.siafoo.net/snippet/258
  6.  * Copyright 2009 Stou Sandalski (Siafoo.net)
  7.  * Copyright 1999-2008 The Apache Software Foundation
  8.  *
  9.  * Licensed under the Apache License, Version 2.0 (the "License");
  10.  * you may not use this file except in compliance with the License.
  11.  * You may obtain a copy of the License at
  12.  *
  13.  * http://www.apache.org/licenses/LICENSE-2.0
  14.  *
  15.  * Unless required by applicable law or agreed to in writing, software
  16.  * distributed under the License is distributed on an "AS IS" BASIS,
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18.  * See the License for the specific language governing permissions and
  19.  * limitations under the License.
  20.  *
  21.  */
  22.  
  23. import java.io.InputStream;
  24. import java.io.IOException;
  25. import java.io.OutputStream;
  26. import java.net.URI;
  27. import java.net.URISyntaxException;
  28. import java.util.Enumeration;
  29.  
  30. import javax.servlet.http.HttpServlet;
  31. import javax.servlet.http.HttpServletRequest;
  32. import javax.servlet.http.HttpServletResponse;
  33. import javax.servlet.ServletException;
  34.  
  35. import org.apache.http.client.HttpClient;
  36. import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
  37. import org.apache.http.client.methods.HttpRequestBase;
  38. import org.apache.http.entity.InputStreamEntity;
  39. import org.apache.http.Header;
  40. import org.apache.http.HttpEntity;
  41. import org.apache.http.HttpResponse;
  42. import org.apache.http.impl.client.DefaultHttpClient;
  43. import org.apache.http.StatusLine;
  44.  
  45. /**
  46. * This servlet provides a proxy to other servers for use in development with GWT devmode.
  47. * It is not meant, in any way shape or form, to be used in production.
  48. */
  49. public class ProxyServlet extends HttpServlet {
  50.  
  51. private static final String targetServer = "http://localhost/";
  52.  
  53. @Override
  54. @SuppressWarnings("unchecked")
  55. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  56. // Create new client to perform the proxied request
  57. HttpClient httpclient = new DefaultHttpClient();
  58.  
  59. // Determine final URL
  60. uri.append(targetServer);
  61. uri.append(req.getRequestURI());
  62.  
  63. // Add any supplied query strings
  64. String queryString = req.getQueryString();
  65. if (queryString != null){
  66. uri.append("?" + queryString);
  67. }
  68.  
  69. // Get HTTP method
  70. final String method = req.getMethod();
  71. // Create new HTTP request container
  72. HttpRequestBase request = null;
  73.  
  74. // Get content length
  75. int contentLength = req.getContentLength();
  76. // Unknown content length ...
  77. // if (contentLength == -1)
  78. // throw new ServletException("Cannot handle unknown content length");
  79. // If we don't have an entity body, things are quite simple
  80. if (contentLength < 1) {
  81. request = new HttpRequestBase() {
  82. public String getMethod() {
  83. return method;
  84. }
  85. };
  86. }
  87. else {
  88. // Prepare request
  89. HttpEntityEnclosingRequestBase tmpRequest = new HttpEntityEnclosingRequestBase() {
  90. public String getMethod() {
  91. return method;
  92. }
  93. };
  94.  
  95. // Transfer entity body from the received request to the new request
  96. InputStreamEntity entity = new InputStreamEntity(req.getInputStream(), contentLength);
  97. tmpRequest.setEntity(entity);
  98.  
  99. request = tmpRequest;
  100. }
  101.  
  102. // Set URI
  103. try {
  104. request.setURI(new URI(uri.toString()));
  105. }
  106. catch (URISyntaxException e) {
  107. throw new ServletException("URISyntaxException: " + e.getMessage());
  108. }
  109.  
  110. // Copy headers from old request to new request
  111. // @todo not sure how this handles multiple headers with the same name
  112. Enumeration<String> headers = req.getHeaderNames();
  113. while (headers.hasMoreElements()) {
  114. String headerName = headers.nextElement();
  115. String headerValue = req.getHeader(headerName);
  116. // Skip Content-Length and Host
  117. String lowerHeader = headerName.toLowerCase();
  118. if (lowerHeader.equals("content-length") == false && lowerHeader.equals("host") == false) {
  119. // System.out.println(headerName.toLowerCase() + ": " + headerValue);
  120. request.addHeader(headerName, headerValue);
  121. }
  122. }
  123.  
  124. // Execute the request
  125. HttpResponse response = httpclient.execute(request);
  126.  
  127. // Transfer status code to the response
  128. StatusLine status = response.getStatusLine();
  129. resp.setStatus(status.getStatusCode());
  130. // resp.setStatus(status.getStatusCode(), status.getReasonPhrase()); // This seems to be deprecated. Yes status message is "ambigous", but I don't approve
  131.  
  132. // Transfer headers to the response
  133. Header[] responseHeaders = response.getAllHeaders();
  134. for (int i=0 ; i<responseHeaders.length ; i++) {
  135. Header header = responseHeaders[i];
  136. resp.addHeader(header.getName(), header.getValue());
  137. }
  138.  
  139. // Transfer proxy response entity to the servlet response
  140. HttpEntity entity = response.getEntity();
  141. InputStream input = entity.getContent();
  142. OutputStream output = resp.getOutputStream();
  143. int b = input.read();
  144. while (b != -1) {
  145. output.write(b);
  146. b = input.read();
  147. }
  148.  
  149. // Clean up
  150. input.close();
  151. output.close();
  152. httpclient.getConnectionManager().shutdown();
  153. }
  154. }
plain

Once that’s up and running, you need to add something along these lines to your web.xml in the WEB-INF directory:

  1. <servlet>
  2. <servlet-name>proxyServlet</servlet-name>
  3. <servlet-class>com.package.server.ProxyServlet</servlet-class>
  4. </servlet>
  5.  
  6. <servlet-mapping>
  7. <servlet-name>proxyServlet</servlet-name>
  8. <url-pattern>/api/*</url-pattern>
  9. </servlet-mapping>
plain