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.
- package com.package.server;
-
- /**
- * Copyright 2010 Kenneth Jorgensen (kennethjorgensen.com) (modifications)
- * - original code can be found at http://www.siafoo.net/snippet/258
- * Copyright 2009 Stou Sandalski (Siafoo.net)
- * Copyright 1999-2008 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
- import java.io.InputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.util.Enumeration;
-
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.ServletException;
-
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
- import org.apache.http.client.methods.HttpRequestBase;
- import org.apache.http.entity.InputStreamEntity;
- import org.apache.http.Header;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.apache.http.StatusLine;
-
- /**
- * This servlet provides a proxy to other servers for use in development with GWT devmode.
- * It is not meant, in any way shape or form, to be used in production.
- */
- public class ProxyServlet extends HttpServlet {
-
-
- @Override
- @SuppressWarnings("unchecked")
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- // Create new client to perform the proxied request
- HttpClient httpclient = new DefaultHttpClient();
-
- // Determine final URL
- uri.append(targetServer);
- uri.append(req.getRequestURI());
-
- // Add any supplied query strings
- if (queryString != null){
- uri.append("?" + queryString);
- }
-
- // Get HTTP method
- // Create new HTTP request container
- HttpRequestBase request = null;
-
- // Get content length
- int contentLength = req.getContentLength();
- // Unknown content length ...
- // if (contentLength == -1)
- // throw new ServletException("Cannot handle unknown content length");
- // If we don't have an entity body, things are quite simple
- if (contentLength < 1) {
- request = new HttpRequestBase() {
- return method;
- }
- };
- }
- else {
- // Prepare request
- HttpEntityEnclosingRequestBase tmpRequest = new HttpEntityEnclosingRequestBase() {
- return method;
- }
- };
-
- // Transfer entity body from the received request to the new request
- InputStreamEntity entity = new InputStreamEntity(req.getInputStream(), contentLength);
- tmpRequest.setEntity(entity);
-
- request = tmpRequest;
- }
-
- // Set URI
- try {
- request.setURI(new URI(uri.toString()));
- }
- catch (URISyntaxException e) {
- throw new ServletException("URISyntaxException: " + e.getMessage());
- }
-
- // Copy headers from old request to new request
- // @todo not sure how this handles multiple headers with the same name
- Enumeration<String> headers = req.getHeaderNames();
- while (headers.hasMoreElements()) {
- // Skip Content-Length and Host
- if (lowerHeader.equals("content-length") == false && lowerHeader.equals("host") == false) {
- // System.out.println(headerName.toLowerCase() + ": " + headerValue);
- request.addHeader(headerName, headerValue);
- }
- }
-
- // Execute the request
- HttpResponse response = httpclient.execute(request);
-
- // Transfer status code to the response
- StatusLine status = response.getStatusLine();
- resp.setStatus(status.getStatusCode());
- // resp.setStatus(status.getStatusCode(), status.getReasonPhrase()); // This seems to be deprecated. Yes status message is "ambigous", but I don't approve
-
- // Transfer headers to the response
- Header[] responseHeaders = response.getAllHeaders();
- for (int i=0 ; i<responseHeaders.length ; i++) {
- Header header = responseHeaders[i];
- resp.addHeader(header.getName(), header.getValue());
- }
-
- // Transfer proxy response entity to the servlet response
- HttpEntity entity = response.getEntity();
- int b = input.read();
- while (b != -1) {
- output.write(b);
- b = input.read();
- }
-
- // Clean up
- input.close();
- output.close();
- httpclient.getConnectionManager().shutdown();
- }
- }
plainOnce that’s up and running, you need to add something along these lines to your web.xml in the WEB-INF directory:
- <servlet>
- <servlet-name>proxyServlet</servlet-name>
- <servlet-class>com.package.server.ProxyServlet</servlet-class>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>proxyServlet</servlet-name>
- <url-pattern>/api/*</url-pattern>
- </servlet-mapping>
plain