You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获基于Google Web Toolkit的旧应用的所有HTTP请求与响应?

Capturing HTTP Requests & Responses for a GWT App on Tomcat 9

Hey there! Let's work through how to capture all incoming requests and outgoing responses for your old GWT app running on Tomcat 9. It sounds like your initial Tomcat-level attempt didn't pan out, so let's break down reliable, actionable methods tailored to your setup.

1. Custom Tomcat Valve (Global/Application-Specific)

Tomcat Valves are designed to intercept requests and responses at the server or application level—this is probably what you tried before, but maybe the configuration or implementation was off. Here's how to get it right:

Step 1: Create a Custom Valve Class

Extend ValveBase and override the invoke method to log request and response details. Make sure to handle both request metadata and content, plus response status and output.

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import javax.servlet.ServletException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class RequestResponseCaptureValve extends ValveBase {

    @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {
        // Capture request details
        String method = request.getMethod();
        String url = request.getRequestURI();
        String queryString = request.getQueryString();
        String requestBody = new String(request.getInputStream().readAllBytes(), StandardCharsets.UTF_8);

        System.out.printf("Incoming Request: %s %s?%s%nBody:%n%s%n", method, url, queryString, requestBody);

        // Let the request proceed to the app
        getNext().invoke(request, response);

        // Capture response details after processing
        int statusCode = response.getStatus();
        String responseBody = new String(response.getContentByteArray(), StandardCharsets.UTF_8);

        System.out.printf("Outgoing Response: Status %d%nBody:%n%s%n", statusCode, responseBody);
    }
}

Step 2: Deploy & Configure the Valve

  • Compile this class into a JAR and place it in Tomcat_HOME/lib.
  • To apply it only to your GWT app, edit the app's META-INF/context.xml and add:
    <Valve className="com.yourpackage.RequestResponseCaptureValve" />
    
  • For global Tomcat-wide capture, add the same <Valve> tag inside the <Host> element in Tomcat_HOME/conf/server.xml.

Note: If you're using Tomcat 9, make sure your Valve class is compatible with Servlet 4.0 APIs, and avoid blocking the request/response flow—always call getNext().invoke() to pass control along.

2. Servlet Filter (Application-Only, No Tomcat Global Changes)

If you don't want to modify Tomcat's global config, a Servlet Filter is perfect—it runs within your GWT app's context and intercepts all requests/responses targeted at it.

Step 1: Create a Response Wrapper to Capture Output

Since the default HttpServletResponse doesn't let you read the response body after it's written, you'll need a wrapper to capture it:

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

public class CapturableResponseWrapper extends HttpServletResponseWrapper {
    private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    private PrintWriter printWriter;

    public CapturableResponseWrapper(HttpServletResponse response) {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new ServletOutputStream() {
            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setWriteListener(WriteListener writeListener) {
                // Not needed for basic capture
            }

            @Override
            public void write(int b) throws IOException {
                byteArrayOutputStream.write(b);
                getResponse().getOutputStream().write(b);
            }
        };
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        if (printWriter == null) {
            printWriter = new PrintWriter(byteArrayOutputStream);
        }
        return printWriter;
    }

    public String getResponseBody() {
        if (printWriter != null) {
            printWriter.flush();
        }
        return byteArrayOutputStream.toString();
    }
}

Step 2: Create the Filter Class

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class RequestResponseCaptureFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Initialize if needed
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        CapturableResponseWrapper wrappedResponse = new CapturableResponseWrapper((HttpServletResponse) response);

        // Capture request details
        String method = httpRequest.getMethod();
        String url = httpRequest.getRequestURI();
        String queryString = httpRequest.getQueryString();
        String requestBody = new String(httpRequest.getInputStream().readAllBytes(), StandardCharsets.UTF_8);

        System.out.printf("Filter: Incoming Request - %s %s?%s%nBody:%n%s%n", method, url, queryString, requestBody);

        // Pass request to the app
        chain.doFilter(httpRequest, wrappedResponse);

        // Capture response details
        int statusCode = wrappedResponse.getStatus();
        String responseBody = wrappedResponse.getResponseBody();

        System.out.printf("Filter: Outgoing Response - Status %d%nBody:%n%s%n", statusCode, responseBody);
    }

    @Override
    public void destroy() {
        // Cleanup if needed
    }
}

Step 3: Register the Filter in web.xml

Add this to your GWT app's WEB-INF/web.xml to map the filter to all requests:

<filter>
    <filter-name>RequestResponseCaptureFilter</filter-name>
    <filter-class>com.yourpackage.RequestResponseCaptureFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>RequestResponseCaptureFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3. GWT RPC-Specific Capture (If Focused on RPC Calls)

If most of your app's traffic is GWT RPC requests (the core of GWT's client-server communication), you can extend the GWT RemoteServiceServlet to log RPC payloads directly:

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;

public class LoggingRemoteServiceServlet extends RemoteServiceServlet {

    @Override
    public String processCall(String payload) throws IOException {
        HttpServletRequest request = getThreadLocalRequest();
        // Log incoming RPC request
        System.out.printf("RPC Request from %s:%n%s%n", request.getRemoteAddr(), payload);

        // Process the RPC call as usual
        String responsePayload = super.processCall(payload);

        // Log outgoing RPC response
        System.out.printf("RPC Response:%n%s%n", responsePayload);

        return responsePayload;
    }

    // Optional: Override processPost to log raw request body if needed
    @Override
    protected void processPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        BufferedReader reader = request.getReader();
        StringBuilder requestBody = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            requestBody.append(line);
        }
        System.out.printf("Raw RPC Request Body:%n%s%n", requestBody);
        super.processPost(request, response);
    }
}

Then update your GWT service servlets in web.xml to use this subclass instead of the default RemoteServiceServlet.


Why Your Initial Tomcat Attempt Might Have Failed

Common pitfalls include:

  • Incorrect Valve placement: If you added it to the global server.xml but your app is deployed in a separate context, it might not have applied.
  • Not capturing response content: Tomcat's default Valve doesn't capture response bodies by default—you need to explicitly read the response's byte array or use a wrapper.
  • Classpath issues: Your Valve JAR wasn't placed in Tomcat_HOME/lib, so Tomcat couldn't load it.

Pick the method that fits your needs: use the Valve for global capture, the Filter for app-specific changes without touching Tomcat config, or the RPC servlet extension if you only care about GWT's RPC traffic.

内容的提问来源于stack exchange,提问作者CR Sardar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 13:52:43