This is an automated email from the ASF dual-hosted git repository.

jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 78c275e23a refactor: run the HTTP filter as a chain of responsibility 
(#7818)
78c275e23a is described below

commit 78c275e23ab1c7c53bbaa0209dd75a552f3688e5
Author: funkye <[email protected]>
AuthorDate: Sun Nov 30 19:03:36 2025 +0800

    refactor: run the HTTP filter as a chain of responsibility (#7818)
---
 .../rpc/netty/http/BaseHttpChannelHandler.java     |  12 -
 .../core/rpc/netty/http/Http2HttpHandler.java      | 149 ++++++------
 .../core/rpc/netty/http/HttpDispatchHandler.java   | 149 ++++++------
 .../core/rpc/netty/http/RequestParseUtils.java     | 260 +++++++++++++++++++++
 .../core/rpc/netty/http/SimpleHttp2Request.java    |  47 ++++
 .../rpc/netty/http/filter/HttpFilterContext.java   |  35 ++-
 .../rpc/netty/http/filter/HttpRequestFilter.java   |   2 +-
 .../netty/http/filter/HttpRequestFilterChain.java  |  18 +-
 .../http/filter/HttpRequestFilterManager.java      |  10 +-
 .../netty/http/filter/HttpRequestParamWrapper.java | 187 +++++----------
 .../core/rpc/netty/http/Http2HttpHandlerTest.java  | 181 +++++++-------
 .../rpc/netty/http/HttpDispatchHandlerTest.java    |  62 ++---
 .../server/config/SeataNamingserverWebConfig.java  |  39 ----
 .../seata/server/filter/RaftRequestFilter.java     | 110 ++++++---
 .../seata/server/filter/XSSHttpRequestFilter.java  |   9 +-
 ...ta.core.rpc.netty.http.filter.HttpRequestFilter |   3 +-
 .../server/controller/ClusterControllerTest.java   |   4 +-
 17 files changed, 788 insertions(+), 489 deletions(-)

diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/BaseHttpChannelHandler.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/BaseHttpChannelHandler.java
index 1dccda8e0c..995b4efb5f 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/BaseHttpChannelHandler.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/BaseHttpChannelHandler.java
@@ -19,11 +19,7 @@ package org.apache.seata.core.rpc.netty.http;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.netty.channel.SimpleChannelInboundHandler;
 import org.apache.seata.common.thread.NamedThreadFactory;
-import org.apache.seata.core.exception.HttpRequestFilterException;
 import org.apache.seata.core.rpc.netty.NettyServerConfig;
-import org.apache.seata.core.rpc.netty.http.filter.HttpFilterContext;
-import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterChain;
-import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterManager;
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -48,12 +44,4 @@ public abstract class BaseHttpChannelHandler<T> extends 
SimpleChannelInboundHand
     static {
         Runtime.getRuntime().addShutdownHook(new 
Thread(HTTP_HANDLER_THREADS::shutdown));
     }
-
-    /**
-     * The filter has a unified entry point and is called by subclasses at an 
appropriate time
-     */
-    protected final void doFilterInternal(HttpFilterContext<?> context) throws 
HttpRequestFilterException {
-        HttpRequestFilterChain filterChain = 
HttpRequestFilterManager.getFilterChain();
-        filterChain.doFilter(context);
-    }
 }
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandler.java 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandler.java
index 0ef8380500..6285180927 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandler.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandler.java
@@ -23,7 +23,6 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http.QueryStringDecoder;
 import io.netty.handler.codec.http2.DefaultHttp2DataFrame;
 import io.netty.handler.codec.http2.DefaultHttp2Headers;
 import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame;
@@ -33,15 +32,18 @@ import io.netty.handler.codec.http2.Http2HeadersFrame;
 import io.netty.handler.codec.http2.Http2StreamFrame;
 import org.apache.seata.common.rpc.http.HttpContext;
 import org.apache.seata.core.exception.HttpRequestFilterException;
+import org.apache.seata.core.rpc.netty.http.RequestParseUtils.BodyParseResult;
+import org.apache.seata.core.rpc.netty.http.RequestParseUtils.QueryParseResult;
 import org.apache.seata.core.rpc.netty.http.filter.HttpFilterContext;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterChain;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterManager;
 import org.apache.seata.core.rpc.netty.http.filter.HttpRequestParamWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Method;
-import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import static 
org.apache.seata.core.protocol.ProtocolConstants.MAX_FRAME_LENGTH;
@@ -102,61 +104,77 @@ public class Http2HttpHandler extends 
BaseHttpChannelHandler<Http2StreamFrame> {
             HttpMethod method = 
HttpMethod.valueOf(http2Headers.method().toString());
             String path = http2Headers.path().toString();
             String body = bodyBuffer != null ? 
bodyBuffer.toString(StandardCharsets.UTF_8) : "";
-            SimpleHttp2Request request = new SimpleHttp2Request(method, path, 
http2Headers, body);
 
-            // After receiving the complete request, the filtering logic is 
executed
-            HttpFilterContext<SimpleHttp2Request> context =
-                    new HttpFilterContext<>(request, () -> new 
HttpRequestParamWrapper(request));
-            doFilterInternal(context);
+            Map<String, List<String>> headerParams = 
RequestParseUtils.copyHeaders(http2Headers);
+            QueryParseResult queryParseResult = 
RequestParseUtils.parseQuery(path);
+            String requestPath = queryParseResult.getPath();
+            Map<String, List<String>> queryParams = 
queryParseResult.getParameters();
+            BodyParseResult bodyParseResult = 
RequestParseUtils.parseBody(OBJECT_MAPPER, body, http2Headers);
 
-            // reuse HttpDispatchHandler logic
-            boolean keepAlive = true; // In HTTP/2, connections are persistent 
by default
-            QueryStringDecoder queryStringDecoder = new 
QueryStringDecoder(request.getPath());
-            String requestPath = queryStringDecoder.path();
+            SimpleHttp2Request request = new SimpleHttp2Request(
+                    method,
+                    path,
+                    http2Headers,
+                    body,
+                    queryParams,
+                    bodyParseResult.getFormParams(),
+                    headerParams,
+                    bodyParseResult.getJsonParams(),
+                    bodyParseResult.getBodyNode());
+
+            HttpFilterContext<SimpleHttp2Request> context = new 
HttpFilterContext<>(
+                    request,
+                    ctx,
+                    true,
+                    HttpContext.HTTP_2_0,
+                    () -> new HttpRequestParamWrapper(
+                            queryParams,
+                            bodyParseResult.getFormParams(),
+                            headerParams,
+                            bodyParseResult.getJsonParams()));
+
+            // Parse request
+            // queryStringDecoder already computed path/params above
             HttpInvocation httpInvocation = 
ControllerManager.getHttpInvocation(requestPath);
             if (httpInvocation == null) {
                 sendErrorResponse(ctx, HttpResponseStatus.NOT_FOUND);
                 return;
             }
-            HttpContext<SimpleHttp2Request> httpContext =
-                    new HttpContext<>(request, ctx, keepAlive, 
HttpContext.HTTP_2_0);
+
+            context.setAttribute("httpInvocation", httpInvocation);
+            context.setAttribute("httpController", 
httpInvocation.getController());
+            context.setAttribute("handleMethod", httpInvocation.getMethod());
+
             ObjectNode requestDataNode = OBJECT_MAPPER.createObjectNode();
-            requestDataNode.set("param", 
ParameterParser.convertParamMap(queryStringDecoder.parameters()));
-            if (request.getMethod() == HttpMethod.POST
-                    && request.getBody() != null
-                    && !request.getBody().isEmpty()) {
-                CharSequence contentTypeSeq = 
request.getHeaders().get(HttpHeaderNames.CONTENT_TYPE);
-                String contentType = contentTypeSeq != null ? 
contentTypeSeq.toString() : "";
+            requestDataNode.set("param", 
ParameterParser.convertParamMap(queryParams));
+            if (request.getMethod() == HttpMethod.POST && 
request.getBodyNode() != null) {
+                requestDataNode.set("body", request.getBodyNode());
+            }
+            Method handleMethod = httpInvocation.getMethod();
+            Object[] args;
+            try {
+                args = ParameterParser.getArgValues(
+                        httpInvocation.getParamMetaData(), handleMethod, 
requestDataNode, context);
+            } catch (Exception e) {
+                LOGGER.error("Error parsing request arguments for HTTP/2: {}", 
e.getMessage(), e);
+                sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST);
+                return;
+            }
+            context.setAttribute("args", args);
+
+            // Execute filter chain in HTTP thread pool
+            HttpRequestFilterChain filterChain = 
HttpRequestFilterManager.getFilterChain(this::executeFinalAction);
+            HTTP_HANDLER_THREADS.execute(() -> {
                 try {
-                    if (contentType.contains("application/json")) {
-                        ObjectNode bodyDataNode = (ObjectNode) 
OBJECT_MAPPER.readTree(request.getBody());
-                        requestDataNode.set("body", bodyDataNode);
-                    } else if 
(contentType.contains("application/x-www-form-urlencoded")) {
-                        Map<String, String> formParams = new HashMap<>();
-                        String[] pairs = request.getBody().split("&");
-                        for (String pair : pairs) {
-                            String[] kv = pair.split("=", 2);
-                            if (kv.length == 2) {
-                                String key = URLDecoder.decode(kv[0], 
StandardCharsets.UTF_8.name());
-                                String value = URLDecoder.decode(kv[1], 
StandardCharsets.UTF_8.name());
-                                formParams.put(key, value);
-                            }
-                        }
-                        ObjectNode formDataNode = 
OBJECT_MAPPER.valueToTree(formParams);
-                        requestDataNode.set("body", formDataNode);
-                    }
+                    filterChain.doFilter(context);
+                } catch (HttpRequestFilterException e) {
+                    LOGGER.warn("Request blocked by filter while processing 
HTTP2 request: {}", e.getMessage());
+                    sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST);
                 } catch (Exception e) {
-                    LOGGER.warn("Failed to parse http2 body: {}", 
e.getMessage());
+                    LOGGER.error("Exception occurred while processing HTTP2 
request: {}", e.getMessage(), e);
+                    sendErrorResponse(ctx, 
HttpResponseStatus.INTERNAL_SERVER_ERROR);
                 }
-            }
-            Object httpController = httpInvocation.getController();
-            Method handleMethod = httpInvocation.getMethod();
-            Object[] args = ParameterParser.getArgValues(
-                    httpInvocation.getParamMetaData(), handleMethod, 
requestDataNode, httpContext);
-            handle(httpController, handleMethod, args, ctx, httpContext);
-        } catch (HttpRequestFilterException e) {
-            LOGGER.warn("Request blocked by filter while processing HTTP2 
request: {}", e.getMessage());
-            sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST);
+            });
         } catch (Exception e) {
             LOGGER.error("Exception occurred while processing HTTP2 request: 
{}", e.getMessage(), e);
             sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
@@ -170,27 +188,24 @@ public class Http2HttpHandler extends 
BaseHttpChannelHandler<Http2StreamFrame> {
         }
     }
 
-    private void handle(
-            Object httpController,
-            Method handleMethod,
-            Object[] args,
-            ChannelHandlerContext ctx,
-            HttpContext<SimpleHttp2Request> httpContext) {
-        HTTP_HANDLER_THREADS.execute(() -> {
-            Object result;
-            try {
-                result = handleMethod.invoke(httpController, args);
-                if (!httpContext.isAsync()) {
-                    sendResponse(ctx, result);
-                }
-            } catch (IllegalAccessException e) {
-                LOGGER.error("Illegal argument exception: {}", e.getMessage(), 
e);
-                sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST);
-            } catch (Exception e) {
-                LOGGER.error("Exception occurred while processing HTTP2 
request: {}", e.getMessage(), e);
-                sendErrorResponse(ctx, 
HttpResponseStatus.INTERNAL_SERVER_ERROR);
+    private void executeFinalAction(HttpFilterContext<?> context) {
+        HttpInvocation httpInvocation = context.getAttribute("httpInvocation");
+        Object httpController = context.getAttribute("httpController");
+        Method handleMethod = context.getAttribute("handleMethod");
+        Object[] args = context.getAttribute("args");
+
+        try {
+            Object result = handleMethod.invoke(httpController, args);
+            if (!context.isAsync()) {
+                sendResponse(context.getContext(), result);
             }
-        });
+        } catch (IllegalAccessException e) {
+            LOGGER.error("Illegal argument exception: {}", e.getMessage(), e);
+            sendErrorResponse(context.getContext(), 
HttpResponseStatus.BAD_REQUEST);
+        } catch (Exception e) {
+            LOGGER.error("Exception occurred while processing HTTP2 request: 
{}", e.getMessage(), e);
+            sendErrorResponse(context.getContext(), 
HttpResponseStatus.INTERNAL_SERVER_ERROR);
+        }
     }
 
     private void sendResponse(ChannelHandlerContext ctx, Object result) throws 
Exception {
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandler.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandler.java
index caafc308fd..a8f9022f08 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandler.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandler.java
@@ -22,6 +22,7 @@ import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.codec.http.FullHttpResponse;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpMethod;
@@ -29,19 +30,20 @@ import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpUtil;
 import io.netty.handler.codec.http.HttpVersion;
-import io.netty.handler.codec.http.QueryStringDecoder;
-import io.netty.handler.codec.http.multipart.Attribute;
-import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
-import io.netty.handler.codec.http.multipart.InterfaceHttpData;
 import org.apache.seata.common.rpc.http.HttpContext;
 import org.apache.seata.core.exception.HttpRequestFilterException;
+import org.apache.seata.core.rpc.netty.http.RequestParseUtils.BodyParseResult;
+import org.apache.seata.core.rpc.netty.http.RequestParseUtils.QueryParseResult;
 import org.apache.seata.core.rpc.netty.http.filter.HttpFilterContext;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterChain;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterManager;
 import org.apache.seata.core.rpc.netty.http.filter.HttpRequestParamWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Method;
-import java.util.concurrent.RejectedExecutionException;
+import java.util.List;
+import java.util.Map;
 
 /**
  * A Netty HTTP request handler that dispatches incoming requests to 
corresponding controller methods
@@ -52,85 +54,86 @@ public class HttpDispatchHandler extends 
BaseHttpChannelHandler<HttpRequest> {
 
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, HttpRequest 
httpRequest) {
-        try {
-            HttpFilterContext<HttpRequest> context =
-                    new HttpFilterContext<>(httpRequest, () -> new 
HttpRequestParamWrapper(httpRequest));
-            doFilterInternal(context);
-        } catch (HttpRequestFilterException e) {
-            LOGGER.warn("Request blocked by filter: {}", e.getMessage());
-            sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST, false);
-            return;
-        } catch (Exception e) {
-            LOGGER.error("Unexpected error during filter execution: {}", 
e.getMessage(), e);
-            sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, 
false);
+        FullHttpRequest fullHttpRequest = httpRequest instanceof 
FullHttpRequest ? (FullHttpRequest) httpRequest : null;
+        QueryParseResult queryParseResult = 
RequestParseUtils.parseQuery(httpRequest.uri());
+        String path = queryParseResult.getPath();
+        Map<String, List<String>> queryParams = 
queryParseResult.getParameters();
+        Map<String, List<String>> headerParams = 
RequestParseUtils.copyHeaders(httpRequest.headers());
+        BodyParseResult bodyParseResult = fullHttpRequest != null
+                ? RequestParseUtils.parseBody(OBJECT_MAPPER, fullHttpRequest)
+                : RequestParseUtils.BodyParseResult.empty();
+
+        HttpFilterContext<HttpRequest> context = new HttpFilterContext<>(
+                httpRequest,
+                ctx,
+                HttpUtil.isKeepAlive(httpRequest)
+                        && httpRequest.protocolVersion().isKeepAliveDefault(),
+                HttpContext.HTTP_1_1,
+                () -> new HttpRequestParamWrapper(
+                        queryParams, bodyParseResult.getFormParams(), 
headerParams, bodyParseResult.getJsonParams()));
+
+        HttpInvocation httpInvocation = 
ControllerManager.getHttpInvocation(path);
+
+        if (httpInvocation == null) {
+            sendErrorResponse(ctx, HttpResponseStatus.NOT_FOUND, false);
             return;
         }
 
+        context.setAttribute("httpInvocation", httpInvocation);
+        context.setAttribute("httpController", httpInvocation.getController());
+        context.setAttribute("handleMethod", httpInvocation.getMethod());
+
+        ObjectNode requestDataNode = OBJECT_MAPPER.createObjectNode();
+        requestDataNode.set("param", 
ParameterParser.convertParamMap(queryParams));
+        if (httpRequest.method() == HttpMethod.POST && 
bodyParseResult.getBodyNode() != null) {
+            requestDataNode.set("body", bodyParseResult.getBodyNode());
+        }
+
+        Object[] args;
         try {
-            boolean keepAlive = HttpUtil.isKeepAlive(httpRequest)
-                    && httpRequest.protocolVersion().isKeepAliveDefault();
-            QueryStringDecoder queryStringDecoder = new 
QueryStringDecoder(httpRequest.uri());
-            String path = queryStringDecoder.path();
-            HttpInvocation httpInvocation = 
ControllerManager.getHttpInvocation(path);
-
-            if (httpInvocation == null) {
-                sendErrorResponse(ctx, HttpResponseStatus.NOT_FOUND, false);
-                return;
-            }
+            args = ParameterParser.getArgValues(
+                    httpInvocation.getParamMetaData(), 
httpInvocation.getMethod(), requestDataNode, context);
+        } catch (Exception e) {
+            LOGGER.error("Error parsing request arguments: {}", 
e.getMessage(), e);
+            sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST, false);
+            return;
+        }
+        context.setAttribute("args", args);
 
-            HttpContext<HttpRequest> httpContext = new 
HttpContext<>(httpRequest, ctx, keepAlive, HttpContext.HTTP_1_1);
-            ObjectNode requestDataNode = OBJECT_MAPPER.createObjectNode();
-            requestDataNode.set("param", 
ParameterParser.convertParamMap(queryStringDecoder.parameters()));
-
-            if (httpRequest.method() == HttpMethod.POST) {
-                HttpPostRequestDecoder httpPostRequestDecoder = null;
-                try {
-                    httpPostRequestDecoder = new 
HttpPostRequestDecoder(httpRequest);
-                    ObjectNode bodyDataNode = OBJECT_MAPPER.createObjectNode();
-                    for (InterfaceHttpData interfaceHttpData : 
httpPostRequestDecoder.getBodyHttpDatas()) {
-                        if (interfaceHttpData.getHttpDataType() != 
InterfaceHttpData.HttpDataType.Attribute) {
-                            continue;
-                        }
-                        Attribute attribute = (Attribute) interfaceHttpData;
-                        bodyDataNode.put(attribute.getName(), 
attribute.getValue());
-                    }
-                    requestDataNode.putIfAbsent("body", bodyDataNode);
-                } finally {
-                    if (httpPostRequestDecoder != null) {
-                        httpPostRequestDecoder.destroy();
-                    }
-                }
+        // Execute filter chain in HTTP thread pool
+        HttpRequestFilterChain filterChain = 
HttpRequestFilterManager.getFilterChain(this::executeFinalAction);
+        HTTP_HANDLER_THREADS.execute(() -> {
+            try {
+                filterChain.doFilter(context);
+            } catch (HttpRequestFilterException e) {
+                LOGGER.warn("Request blocked by filter: {}", e.getMessage());
+                sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST, false);
+            } catch (Exception e) {
+                LOGGER.error("Unexpected error during request processing: {}", 
e.getMessage(), e);
+                sendErrorResponse(ctx, 
HttpResponseStatus.INTERNAL_SERVER_ERROR, false);
             }
+        });
+    }
 
-            Object httpController = httpInvocation.getController();
-            Method handleMethod = httpInvocation.getMethod();
-            Object[] args = ParameterParser.getArgValues(
-                    httpInvocation.getParamMetaData(), handleMethod, 
requestDataNode, httpContext);
+    private void executeFinalAction(HttpFilterContext<?> context) {
+        HttpInvocation httpInvocation = context.getAttribute("httpInvocation");
+        Object httpController = context.getAttribute("httpController");
+        Method handleMethod = context.getAttribute("handleMethod");
+        Object[] args = context.getAttribute("args");
 
-            try {
-                HTTP_HANDLER_THREADS.execute(() -> {
-                    try {
-                        Object result = handleMethod.invoke(httpController, 
args);
-                        if (httpContext.isAsync()) {
-                            return;
-                        }
-
-                        sendResponse(ctx, keepAlive, result);
-                    } catch (IllegalArgumentException e) {
-                        LOGGER.error("Illegal argument exception: {}", 
e.getMessage(), e);
-                        sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST, 
false);
-                    } catch (Exception e) {
-                        LOGGER.error("Exception occurred while processing HTTP 
request: {}", e.getMessage(), e);
-                        sendErrorResponse(ctx, 
HttpResponseStatus.INTERNAL_SERVER_ERROR, false);
-                    }
-                });
-            } catch (RejectedExecutionException e) {
-                LOGGER.error("HTTP thread pool is full: {}", e.getMessage(), 
e);
-                sendErrorResponse(ctx, HttpResponseStatus.SERVICE_UNAVAILABLE, 
false);
+        try {
+            Object result = handleMethod.invoke(httpController, args);
+            if (context.isAsync()) {
+                return;
             }
+
+            sendResponse(context.getContext(), context.isKeepAlive(), result);
+        } catch (IllegalArgumentException e) {
+            LOGGER.error("Illegal argument exception: {}", e.getMessage(), e);
+            sendErrorResponse(context.getContext(), 
HttpResponseStatus.BAD_REQUEST, false);
         } catch (Exception e) {
             LOGGER.error("Exception occurred while processing HTTP request: 
{}", e.getMessage(), e);
-            sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, 
false);
+            sendErrorResponse(context.getContext(), 
HttpResponseStatus.INTERNAL_SERVER_ERROR, false);
         }
     }
 
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/RequestParseUtils.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/RequestParseUtils.java
new file mode 100644
index 0000000000..dd7516bb62
--- /dev/null
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/RequestParseUtils.java
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.seata.core.rpc.netty.http;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import io.netty.handler.codec.http.multipart.Attribute;
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
+import io.netty.handler.codec.http.multipart.InterfaceHttpData;
+import io.netty.handler.codec.http2.Http2Headers;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Utility class that parses HTTP headers, query parameters and body payloads 
so handlers can reuse the same results.
+ */
+public final class RequestParseUtils {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(RequestParseUtils.class);
+
+    private RequestParseUtils() {}
+
+    public static QueryParseResult parseQuery(String uri) {
+        QueryStringDecoder decoder = new QueryStringDecoder(uri);
+        return new QueryParseResult(decoder.path(), 
deepCopyParameters(decoder.parameters()));
+    }
+
+    public static Map<String, List<String>> copyHeaders(HttpHeaders headers) {
+        Map<String, List<String>> headerParams = new HashMap<>();
+        for (Map.Entry<String, String> entry : headers) {
+            String key = entry.getKey();
+            headerParams.computeIfAbsent(key, k -> new 
ArrayList<>()).add(entry.getValue());
+            String lowerKey = key != null ? key.toLowerCase(Locale.ROOT) : 
null;
+            if (lowerKey != null && !lowerKey.equals(key)) {
+                headerParams.computeIfAbsent(lowerKey, k -> new 
ArrayList<>()).add(entry.getValue());
+            }
+        }
+        return headerParams;
+    }
+
+    public static Map<String, List<String>> copyHeaders(Http2Headers headers) {
+        Map<String, List<String>> headerParams = new HashMap<>();
+        for (Map.Entry<CharSequence, CharSequence> entry : headers) {
+            String key = entry.getKey().toString();
+            String value = entry.getValue().toString();
+            headerParams.computeIfAbsent(key, k -> new 
ArrayList<>()).add(value);
+            String lowerKey = key.toLowerCase(Locale.ROOT);
+            if (!lowerKey.equals(key)) {
+                headerParams.computeIfAbsent(lowerKey, k -> new 
ArrayList<>()).add(value);
+            }
+        }
+        return headerParams;
+    }
+
+    public static Map<String, List<String>> deepCopyParameters(Map<String, 
List<String>> source) {
+        Map<String, List<String>> target = new HashMap<>();
+        if (source == null) {
+            return target;
+        }
+        source.forEach((key, values) -> {
+            if (values != null) {
+                target.put(key, new ArrayList<>(values));
+            }
+        });
+        return target;
+    }
+
+    public static BodyParseResult parseBody(ObjectMapper objectMapper, 
FullHttpRequest request) {
+        if (request == null || !request.content().isReadable()) {
+            return BodyParseResult.empty();
+        }
+        String contentType = 
request.headers().get(HttpHeaderNames.CONTENT_TYPE);
+        if (contentType == null) {
+            return BodyParseResult.empty();
+        }
+        String lowerCaseContentType = contentType.toLowerCase(Locale.ROOT);
+        String bodyString = request.content().toString(StandardCharsets.UTF_8);
+
+        Map<String, List<String>> formParams = new HashMap<>();
+        Map<String, List<String>> jsonParams = new HashMap<>();
+        ObjectNode bodyNode = null;
+
+        try {
+            if (lowerCaseContentType.contains("application/json")) {
+                JsonNode node = objectMapper.readTree(bodyString);
+                if (node instanceof ObjectNode) {
+                    bodyNode = (ObjectNode) node;
+                    bodyNode.fields().forEachRemaining(entry -> jsonParams
+                            .computeIfAbsent(entry.getKey(), k -> new 
ArrayList<>())
+                            .add(entry.getValue().asText()));
+                }
+            } else if 
(lowerCaseContentType.contains("application/x-www-form-urlencoded")) {
+                bodyNode = objectMapper.createObjectNode();
+                decodeUrlEncoded(bodyString, formParams, bodyNode);
+            } else if (lowerCaseContentType.contains("multipart/form-data")) {
+                bodyNode = objectMapper.createObjectNode();
+                HttpPostRequestDecoder decoder = null;
+                try {
+                    decoder = new HttpPostRequestDecoder(request);
+                    for (InterfaceHttpData data : decoder.getBodyHttpDatas()) {
+                        if (data.getHttpDataType() != 
InterfaceHttpData.HttpDataType.Attribute) {
+                            continue;
+                        }
+                        Attribute attr = (Attribute) data;
+                        try {
+                            String name = attr.getName();
+                            String value = attr.getValue();
+                            formParams
+                                    .computeIfAbsent(name, k -> new 
ArrayList<>())
+                                    .add(value);
+                            bodyNode.put(name, value);
+                        } finally {
+                            attr.release();
+                        }
+                    }
+                } finally {
+                    if (decoder != null) {
+                        decoder.destroy();
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Failed to parse HTTP/1.x body: {}", e.getMessage());
+        }
+        return new BodyParseResult(formParams, jsonParams, bodyNode);
+    }
+
+    public static BodyParseResult parseBody(ObjectMapper objectMapper, String 
body, Http2Headers headers) {
+        if (body == null || body.isEmpty()) {
+            return BodyParseResult.empty();
+        }
+        CharSequence contentTypeSeq = 
headers.get(HttpHeaderNames.CONTENT_TYPE);
+        if (contentTypeSeq == null) {
+            return BodyParseResult.empty();
+        }
+        String contentType = contentTypeSeq.toString();
+        String lowerCaseContentType = contentType.toLowerCase(Locale.ROOT);
+
+        Map<String, List<String>> formParams = new HashMap<>();
+        Map<String, List<String>> jsonParams = new HashMap<>();
+        ObjectNode bodyNode = null;
+        try {
+            if (lowerCaseContentType.contains("application/json")) {
+                JsonNode node = objectMapper.readTree(body);
+                if (node instanceof ObjectNode) {
+                    bodyNode = (ObjectNode) node;
+                    bodyNode.fields().forEachRemaining(entry -> jsonParams
+                            .computeIfAbsent(entry.getKey(), k -> new 
ArrayList<>())
+                            .add(entry.getValue().asText()));
+                }
+            } else if 
(lowerCaseContentType.contains("application/x-www-form-urlencoded")) {
+                bodyNode = objectMapper.createObjectNode();
+                decodeUrlEncoded(body, formParams, bodyNode);
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Failed to parse HTTP/2 body: {}", e.getMessage());
+        }
+        return new BodyParseResult(formParams, jsonParams, bodyNode);
+    }
+
+    private static void decodeUrlEncoded(String body, Map<String, 
List<String>> formParams, ObjectNode bodyNode) {
+        if (body == null || body.isEmpty()) {
+            return;
+        }
+        String[] pairs = body.split("&");
+        for (String pair : pairs) {
+            String[] kv = pair.split("=", 2);
+            if (kv.length != 2) {
+                continue;
+            }
+            String key = decodeComponent(kv[0]);
+            String value = decodeComponent(kv[1]);
+            formParams.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
+            bodyNode.put(key, value);
+        }
+    }
+
+    private static String decodeComponent(String value) {
+        try {
+            return URLDecoder.decode(value, StandardCharsets.UTF_8.name());
+        } catch (Exception e) {
+            LOGGER.warn("Failed to decode form field: {}", value);
+            return value;
+        }
+    }
+
+    public static final class QueryParseResult {
+        private final String path;
+        private final Map<String, List<String>> parameters;
+
+        QueryParseResult(String path, Map<String, List<String>> parameters) {
+            this.path = path;
+            this.parameters = parameters;
+        }
+
+        public String getPath() {
+            return path;
+        }
+
+        public Map<String, List<String>> getParameters() {
+            return parameters;
+        }
+    }
+
+    public static final class BodyParseResult {
+        private final Map<String, List<String>> formParams;
+        private final Map<String, List<String>> jsonParams;
+        private final ObjectNode bodyNode;
+
+        BodyParseResult(
+                Map<String, List<String>> formParams, Map<String, 
List<String>> jsonParams, ObjectNode bodyNode) {
+            this.formParams = formParams;
+            this.jsonParams = jsonParams;
+            this.bodyNode = bodyNode;
+        }
+
+        public static BodyParseResult empty() {
+            return new BodyParseResult(new HashMap<>(), new HashMap<>(), null);
+        }
+
+        public Map<String, List<String>> getFormParams() {
+            return formParams;
+        }
+
+        public Map<String, List<String>> getJsonParams() {
+            return jsonParams;
+        }
+
+        public ObjectNode getBodyNode() {
+            return bodyNode;
+        }
+    }
+}
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/SimpleHttp2Request.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/SimpleHttp2Request.java
index fe31fb6b7d..3c3c405ea4 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/SimpleHttp2Request.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/SimpleHttp2Request.java
@@ -16,20 +16,47 @@
  */
 package org.apache.seata.core.rpc.netty.http;
 
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http2.Http2Headers;
 
+import java.util.List;
+import java.util.Map;
+
 public class SimpleHttp2Request {
     private final HttpMethod method;
     private final String path;
     private final Http2Headers headers;
     private final String body;
+    private final Map<String, List<String>> queryParams;
+    private final Map<String, List<String>> formParams;
+    private final Map<String, List<String>> headerParams;
+    private final Map<String, List<String>> jsonParams;
+    private final ObjectNode bodyNode;
 
     public SimpleHttp2Request(HttpMethod method, String path, Http2Headers 
headers, String body) {
+        this(method, path, headers, body, null, null, null, null, null);
+    }
+
+    public SimpleHttp2Request(
+            HttpMethod method,
+            String path,
+            Http2Headers headers,
+            String body,
+            Map<String, List<String>> queryParams,
+            Map<String, List<String>> formParams,
+            Map<String, List<String>> headerParams,
+            Map<String, List<String>> jsonParams,
+            ObjectNode bodyNode) {
         this.method = method;
         this.path = path;
         this.headers = headers;
         this.body = body;
+        this.queryParams = queryParams;
+        this.formParams = formParams;
+        this.headerParams = headerParams;
+        this.jsonParams = jsonParams;
+        this.bodyNode = bodyNode;
     }
 
     public HttpMethod getMethod() {
@@ -47,4 +74,24 @@ public class SimpleHttp2Request {
     public String getBody() {
         return body;
     }
+
+    public Map<String, List<String>> getQueryParams() {
+        return queryParams;
+    }
+
+    public Map<String, List<String>> getFormParams() {
+        return formParams;
+    }
+
+    public Map<String, List<String>> getHeaderParams() {
+        return headerParams;
+    }
+
+    public Map<String, List<String>> getJsonParams() {
+        return jsonParams;
+    }
+
+    public ObjectNode getBodyNode() {
+        return bodyNode;
+    }
 }
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpFilterContext.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpFilterContext.java
index 0fac67cab6..e9eb2d9ab2 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpFilterContext.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpFilterContext.java
@@ -16,22 +16,28 @@
  */
 package org.apache.seata.core.rpc.netty.http.filter;
 
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.seata.common.rpc.http.HttpContext;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Supplier;
 
-public class HttpFilterContext<T> {
-    private final T request;
+public class HttpFilterContext<T> extends HttpContext<T> {
     private final Supplier<HttpRequestParamWrapper> paramWrapperSupplier;
     private volatile HttpRequestParamWrapper paramWrapper;
+    private final Map<String, Object> attributes = new ConcurrentHashMap<>();
 
-    public HttpFilterContext(T request, Supplier<HttpRequestParamWrapper> 
paramWrapperSupplier) {
-        this.request = request;
+    public HttpFilterContext(
+            T request,
+            ChannelHandlerContext channelHandlerContext,
+            boolean keepAlive,
+            String httpVersion,
+            Supplier<HttpRequestParamWrapper> paramWrapperSupplier) {
+        super(request, channelHandlerContext, keepAlive, httpVersion);
         this.paramWrapperSupplier = paramWrapperSupplier;
     }
 
-    public T getRequest() {
-        return request;
-    }
-
     public HttpRequestParamWrapper getParamWrapper() {
         if (paramWrapper == null) {
             synchronized (this) {
@@ -42,4 +48,17 @@ public class HttpFilterContext<T> {
         }
         return paramWrapper;
     }
+
+    public void setAttribute(String key, Object value) {
+        attributes.put(key, value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <V> V getAttribute(String key) {
+        return (V) attributes.get(key);
+    }
+
+    public Object removeAttribute(String key) {
+        return attributes.remove(key);
+    }
 }
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilter.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilter.java
index 96728f450e..703395ab9c 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilter.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilter.java
@@ -33,7 +33,7 @@ public interface HttpRequestFilter {
     /**
      * Executes the filter logic.
      */
-    void doFilter(HttpFilterContext<?> context) throws 
HttpRequestFilterException;
+    void doFilter(HttpFilterContext<?> context, HttpRequestFilterChain chain) 
throws HttpRequestFilterException;
 
     /**
      * Determines if the filter should run.
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterChain.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterChain.java
index 7fd774e204..5bae906c4b 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterChain.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterChain.java
@@ -19,17 +19,29 @@ package org.apache.seata.core.rpc.netty.http.filter;
 import org.apache.seata.core.exception.HttpRequestFilterException;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 public class HttpRequestFilterChain {
     private final List<HttpRequestFilter> filters;
+    private final Consumer<HttpFilterContext<?>> finalAction;
+    private int currentIndex = 0;
 
-    public HttpRequestFilterChain(List<HttpRequestFilter> filters) {
+    public HttpRequestFilterChain(List<HttpRequestFilter> filters, 
Consumer<HttpFilterContext<?>> finalAction) {
         this.filters = filters;
+        this.finalAction = finalAction;
     }
 
     public void doFilter(HttpFilterContext<?> httpFilterContext) throws 
HttpRequestFilterException {
-        for (HttpRequestFilter filter : filters) {
-            filter.doFilter(httpFilterContext);
+        if (currentIndex < filters.size()) {
+            HttpRequestFilter filter = filters.get(currentIndex++);
+            filter.doFilter(httpFilterContext, this);
+        } else {
+            // Execute final action
+            if (finalAction != null) {
+                finalAction.accept(httpFilterContext);
+            }
+            // Reset for next request
+            currentIndex = 0;
         }
     }
 
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterManager.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterManager.java
index 5099a60652..6e1949c7af 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterManager.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestFilterManager.java
@@ -21,6 +21,7 @@ import org.apache.seata.common.loader.EnhancedServiceLoader;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.function.Consumer;
 
 public class HttpRequestFilterManager {
 
@@ -42,7 +43,7 @@ public class HttpRequestFilterManager {
         }
         
HTTP_REQUEST_FILTERS.sort(Comparator.comparingInt(HttpRequestFilter::getOrder));
 
-        HTTP_REQUEST_FILTER_CHAIN = new 
HttpRequestFilterChain(HTTP_REQUEST_FILTERS);
+        HTTP_REQUEST_FILTER_CHAIN = new 
HttpRequestFilterChain(HTTP_REQUEST_FILTERS, null);
         initialized = true;
     }
 
@@ -52,4 +53,11 @@ public class HttpRequestFilterManager {
         }
         return HTTP_REQUEST_FILTER_CHAIN;
     }
+
+    public static HttpRequestFilterChain 
getFilterChain(Consumer<HttpFilterContext<?>> finalAction) {
+        if (!initialized) {
+            throw new IllegalStateException("HttpRequestFilterManager not 
initialized.");
+        }
+        return new HttpRequestFilterChain(HTTP_REQUEST_FILTERS, finalAction);
+    }
 }
diff --git 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestParamWrapper.java
 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestParamWrapper.java
index 50af6437ff..afac73af9d 100644
--- 
a/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestParamWrapper.java
+++ 
b/core/src/main/java/org/apache/seata/core/rpc/netty/http/filter/HttpRequestParamWrapper.java
@@ -16,24 +16,17 @@
  */
 package org.apache.seata.core.rpc.netty.http.filter;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.handler.codec.http.DefaultFullHttpRequest;
 import io.netty.handler.codec.http.FullHttpRequest;
-import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.QueryStringDecoder;
-import io.netty.handler.codec.http.multipart.Attribute;
-import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
-import io.netty.handler.codec.http.multipart.InterfaceHttpData;
 import io.netty.handler.codec.http2.Http2Headers;
+import org.apache.seata.core.rpc.netty.http.RequestParseUtils;
 import org.apache.seata.core.rpc.netty.http.SimpleHttp2Request;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -52,146 +45,73 @@ public class HttpRequestParamWrapper {
     private final Map<String, List<String>> headerParams = new HashMap<>();
     private final Map<String, List<String>> jsonParams = new HashMap<>();
 
+    public HttpRequestParamWrapper(
+            Map<String, List<String>> queryParams,
+            Map<String, List<String>> formParams,
+            Map<String, List<String>> headerParams,
+            Map<String, List<String>> jsonParams) {
+        mergeParams(this.queryParams, queryParams);
+        mergeParams(this.formParams, formParams);
+        mergeParams(this.headerParams, headerParams);
+        mergeParams(this.jsonParams, jsonParams);
+    }
+
     public HttpRequestParamWrapper(HttpRequest httpRequest) {
         if (!(httpRequest instanceof FullHttpRequest)) {
             throw new IllegalArgumentException("HttpRequest must be 
FullHttpRequest to read body.");
         }
         FullHttpRequest fullRequest = (FullHttpRequest) httpRequest;
-        parseQueryParams(fullRequest);
-        parseHeaders(fullRequest);
-        parseBody(fullRequest);
+        parseQueryParams(fullRequest.uri());
+        parseHeaders(fullRequest.headers());
+        RequestParseUtils.BodyParseResult bodyParseResult = 
RequestParseUtils.parseBody(OBJECT_MAPPER, fullRequest);
+        mergeParams(formParams, bodyParseResult.getFormParams());
+        mergeParams(jsonParams, bodyParseResult.getJsonParams());
     }
 
     public HttpRequestParamWrapper(SimpleHttp2Request request) {
-        parseQueryParams(request.getPath());
-        parseHeaders(request.getHeaders());
-
-        CharSequence contentTypeSeq = 
request.getHeaders().get(HttpHeaderNames.CONTENT_TYPE);
-        String contentType = contentTypeSeq != null ? 
contentTypeSeq.toString() : null;
-        if (contentType == null) {
-            return;
+        if (request.getQueryParams() != null) {
+            mergeParams(queryParams, request.getQueryParams());
+        } else {
+            parseQueryParams(request.getPath());
         }
 
-        try {
-            if (contentType.contains("application/json")) {
-                parseJsonBody(request.getBody());
-            } else if 
(contentType.contains("application/x-www-form-urlencoded")) {
-                parseFormUrlEncodedBody(request.getBody());
-            }
-        } catch (Exception e) {
-            LOGGER.warn("Failed to parse HTTP/2 body: {}", e.getMessage(), e);
+        if (request.getHeaderParams() != null) {
+            mergeParams(headerParams, request.getHeaderParams());
+        } else if (request.getHeaders() != null) {
+            parseHeaders(request.getHeaders());
         }
-    }
-
-    private void parseQueryParams(FullHttpRequest request) {
-        QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
-        queryParams.putAll(decoder.parameters());
-    }
-
-    private void parseQueryParams(String path) {
-        QueryStringDecoder decoder = new QueryStringDecoder(path);
-        queryParams.putAll(decoder.parameters());
-    }
 
-    private void parseHeaders(FullHttpRequest request) {
-        for (Map.Entry<String, String> entry : request.headers()) {
-            headerParams.computeIfAbsent(entry.getKey(), k -> new 
ArrayList<>()).add(entry.getValue());
+        boolean hasBodyMaps = request.getFormParams() != null || 
request.getJsonParams() != null;
+        if (request.getFormParams() != null) {
+            mergeParams(formParams, request.getFormParams());
         }
-    }
-
-    private void parseHeaders(Http2Headers headers) {
-        for (Map.Entry<CharSequence, CharSequence> entry : headers) {
-            headerParams
-                    .computeIfAbsent(entry.getKey().toString(), k -> new 
ArrayList<>())
-                    .add(entry.getValue().toString());
+        if (request.getJsonParams() != null) {
+            mergeParams(jsonParams, request.getJsonParams());
         }
-    }
 
-    private void parseFormUrlEncodedBody(String body) {
-        if (body == null || body.trim().isEmpty()) {
-            return;
-        }
-        String[] pairs = body.split("&");
-        for (String pair : pairs) {
-            String[] kv = pair.split("=", 2);
-            if (kv.length == 2) {
-                String key = decode(kv[0]);
-                String value = decode(kv[1]);
-                formParams.computeIfAbsent(key, k -> new 
ArrayList<>()).add(value);
-            }
+        if (!hasBodyMaps && request.getBody() != null) {
+            RequestParseUtils.BodyParseResult bodyParseResult =
+                    RequestParseUtils.parseBody(OBJECT_MAPPER, 
request.getBody(), request.getHeaders());
+            mergeParams(formParams, bodyParseResult.getFormParams());
+            mergeParams(jsonParams, bodyParseResult.getJsonParams());
         }
     }
 
-    private String decode(String s) {
-        try {
-            return java.net.URLDecoder.decode(s, 
StandardCharsets.UTF_8.name());
-        } catch (Exception e) {
-            LOGGER.warn("Failed to decode form field: {}", s, e);
-            return s;
-        }
-    }
-
-    private void parseBody(FullHttpRequest request) {
-        String contentType = 
request.headers().get(HttpHeaderNames.CONTENT_TYPE);
-        if (contentType == null) {
-            return;
-        }
-
-        ByteBuf originalContent = request.content();
-        ByteBuf copiedBuf = Unpooled.copiedBuffer(originalContent);
-
-        String bodyStr = copiedBuf.toString(StandardCharsets.UTF_8);
-
-        try {
-            if (contentType.contains("application/json")) {
-                parseJsonBody(bodyStr);
-            } else if 
(contentType.contains("application/x-www-form-urlencoded")
-                    || contentType.contains("multipart/form-data")) {
-                // Replace user-controlled URI with constant string during 
internal FullHttpRequest construction for
-                // decoding form parameters.
-                FullHttpRequest copiedRequest = new DefaultFullHttpRequest(
-                        request.protocolVersion(), request.method(), 
"/internal-safe-uri", copiedBuf);
-                // Copy headers to ensure proper multipart parsing
-                copiedRequest.headers().setAll(request.headers());
-                parseFormBody(copiedRequest);
-            }
-        } catch (Exception e) {
-            LOGGER.warn("Failed to parse HTTP body: {}", e.getMessage(), e);
-        }
+    private void parseQueryParams(String uri) {
+        QueryStringDecoder decoder = new QueryStringDecoder(uri);
+        queryParams.putAll(decoder.parameters());
     }
 
-    private void parseJsonBody(String bodyStr) {
-        try {
-            JsonNode jsonNode = OBJECT_MAPPER.readTree(bodyStr);
-            if (jsonNode != null && jsonNode.isObject()) {
-                jsonNode.fields().forEachRemaining(e -> jsonParams
-                        .computeIfAbsent(e.getKey(), k -> new ArrayList<>())
-                        .add(e.getValue().asText()));
-            }
-        } catch (Exception e) {
-            LOGGER.warn("Failed to parse JSON body: {}", e.getMessage(), e);
-        }
+    private void parseHeaders(HttpHeaders headers) {
+        headers.forEach(entry -> headerParams
+                .computeIfAbsent(entry.getKey(), k -> new ArrayList<>())
+                .add(entry.getValue()));
     }
 
-    private void parseFormBody(FullHttpRequest request) {
-        HttpPostRequestDecoder decoder = null;
-        try {
-            decoder = new HttpPostRequestDecoder(request);
-            for (InterfaceHttpData data : decoder.getBodyHttpDatas()) {
-                if (data.getHttpDataType() == 
InterfaceHttpData.HttpDataType.Attribute) {
-                    Attribute attr = (Attribute) data;
-                    formParams
-                            .computeIfAbsent(attr.getName(), k -> new 
ArrayList<>())
-                            .add(attr.getValue());
-                }
-            }
-        } catch (Exception e) {
-            LOGGER.warn("Failed to parse form body: {}", e.getMessage(), e);
-        } finally {
-            if (decoder != null) {
-                decoder.destroy();
-            }
-        }
+    private void parseHeaders(Http2Headers headers) {
+        headers.forEach(entry -> headerParams
+                .computeIfAbsent(entry.getKey().toString(), k -> new 
ArrayList<>())
+                .add(entry.getValue().toString()));
     }
 
     /**
@@ -211,4 +131,17 @@ public class HttpRequestParamWrapper {
 
         return all;
     }
+
+    private void mergeParams(Map<String, List<String>> target, Map<String, 
List<String>> source) {
+        if (source == null || source.isEmpty()) {
+            return;
+        }
+        source.forEach((key, values) -> {
+            if (values == null || values.isEmpty()) {
+                return;
+            }
+            List<String> targetList = target.computeIfAbsent(key, k -> new 
ArrayList<>());
+            targetList.addAll(values);
+        });
+    }
 }
diff --git 
a/core/src/test/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandlerTest.java
 
b/core/src/test/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandlerTest.java
index b6bdfff899..b68411d52a 100644
--- 
a/core/src/test/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandlerTest.java
+++ 
b/core/src/test/java/org/apache/seata/core/rpc/netty/http/Http2HttpHandlerTest.java
@@ -95,29 +95,26 @@ class Http2HttpHandlerTest {
 
     @Test
     void testHttp2GetRequestWithParameters() throws Exception {
-        try (MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class)) {
-            HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
-            doNothing().when(mockChain).doFilter(any());
-            
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-            Http2Headers headers = new DefaultHttp2Headers();
-            headers.method("GET");
-            headers.path("/test?param=testValue");
-            Http2HeadersFrame headersFrame = new 
DefaultHttp2HeadersFrame(headers, true);
-            channel.writeInbound(headersFrame);
+        HttpRequestFilterManager.initializeFilters();
 
-            Http2StreamFrame responseHeadersFrame = waitForHttp2Response(5000);
-            assertNotNull(responseHeadersFrame);
-            assertTrue(responseHeadersFrame instanceof 
DefaultHttp2HeadersFrame);
-            DefaultHttp2HeadersFrame respHeaders = (DefaultHttp2HeadersFrame) 
responseHeadersFrame;
-            assertEquals("200", respHeaders.headers().status().toString());
-
-            Http2StreamFrame responseDataFrame = waitForHttp2Response(5000);
-            assertNotNull(responseDataFrame);
-            assertTrue(responseDataFrame instanceof DefaultHttp2DataFrame);
-            DefaultHttp2DataFrame respData = (DefaultHttp2DataFrame) 
responseDataFrame;
-            String content = 
respData.content().toString(StandardCharsets.UTF_8);
-            assertTrue(content.contains("Processed: testValue"));
-        }
+        Http2Headers headers = new DefaultHttp2Headers();
+        headers.method("GET");
+        headers.path("/test?param=testValue");
+        Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(headers, 
true);
+        channel.writeInbound(headersFrame);
+
+        Http2StreamFrame responseHeadersFrame = waitForHttp2Response(5000);
+        assertNotNull(responseHeadersFrame);
+        assertTrue(responseHeadersFrame instanceof DefaultHttp2HeadersFrame);
+        DefaultHttp2HeadersFrame respHeaders = (DefaultHttp2HeadersFrame) 
responseHeadersFrame;
+        assertEquals("200", respHeaders.headers().status().toString());
+
+        Http2StreamFrame responseDataFrame = waitForHttp2Response(5000);
+        assertNotNull(responseDataFrame);
+        assertTrue(responseDataFrame instanceof DefaultHttp2DataFrame);
+        DefaultHttp2DataFrame respData = (DefaultHttp2DataFrame) 
responseDataFrame;
+        String content = respData.content().toString(StandardCharsets.UTF_8);
+        assertTrue(content.contains("Processed: testValue"));
     }
 
     @Test
@@ -141,46 +138,43 @@ class Http2HttpHandlerTest {
 
     @Test
     void testHttp2PostRequestWithJsonBody() throws Exception {
-        try (MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class)) {
-            HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
-            doNothing().when(mockChain).doFilter(any());
-            
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-            String json = OBJECT_MAPPER.writeValueAsString(new HashMap<String, 
Object>() {
-                {
-                    put("foo", "bar");
-                }
-            });
-            Http2Headers headers = new DefaultHttp2Headers();
-            headers.method("POST");
-            headers.path("/test?param=jsonValue");
-            Http2HeadersFrame headersFrame = new 
DefaultHttp2HeadersFrame(headers, false);
-            channel.writeInbound(headersFrame);
-            DefaultHttp2DataFrame dataFrame =
-                    new DefaultHttp2DataFrame(Unpooled.copiedBuffer(json, 
StandardCharsets.UTF_8), true);
-            channel.writeInbound(dataFrame);
+        HttpRequestFilterManager.initializeFilters();
 
-            Http2StreamFrame frame1 = null, frame2 = null;
-            long deadline = System.currentTimeMillis() + 5000;
-            while ((frame1 == null || frame2 == null) && 
System.currentTimeMillis() < deadline) {
-                if (frame1 == null) frame1 = channel.readOutbound();
-                if (frame2 == null) frame2 = channel.readOutbound();
-                if (frame1 == null || frame2 == null) Thread.sleep(500);
+        String json = OBJECT_MAPPER.writeValueAsString(new HashMap<String, 
Object>() {
+            {
+                put("foo", "bar");
             }
-            assertNotNull(frame1);
-            assertNotNull(frame2);
-            DefaultHttp2HeadersFrame respHeaders;
-            DefaultHttp2DataFrame respData;
-            if (frame1 instanceof DefaultHttp2HeadersFrame) {
-                respHeaders = (DefaultHttp2HeadersFrame) frame1;
-                respData = (DefaultHttp2DataFrame) frame2;
-            } else {
-                respHeaders = (DefaultHttp2HeadersFrame) frame2;
-                respData = (DefaultHttp2DataFrame) frame1;
-            }
-            assertEquals("200", respHeaders.headers().status().toString());
-            String content = 
respData.content().toString(StandardCharsets.UTF_8);
-            assertTrue(content.contains("Processed: jsonValue"));
+        });
+        Http2Headers headers = new DefaultHttp2Headers();
+        headers.method("POST");
+        headers.path("/test?param=jsonValue");
+        Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(headers, 
false);
+        channel.writeInbound(headersFrame);
+        DefaultHttp2DataFrame dataFrame =
+                new DefaultHttp2DataFrame(Unpooled.copiedBuffer(json, 
StandardCharsets.UTF_8), true);
+        channel.writeInbound(dataFrame);
+
+        Http2StreamFrame frame1 = null, frame2 = null;
+        long deadline = System.currentTimeMillis() + 5000;
+        while ((frame1 == null || frame2 == null) && 
System.currentTimeMillis() < deadline) {
+            if (frame1 == null) frame1 = channel.readOutbound();
+            if (frame2 == null) frame2 = channel.readOutbound();
+            if (frame1 == null || frame2 == null) Thread.sleep(500);
+        }
+        assertNotNull(frame1);
+        assertNotNull(frame2);
+        DefaultHttp2HeadersFrame respHeaders;
+        DefaultHttp2DataFrame respData;
+        if (frame1 instanceof DefaultHttp2HeadersFrame) {
+            respHeaders = (DefaultHttp2HeadersFrame) frame1;
+            respData = (DefaultHttp2DataFrame) frame2;
+        } else {
+            respHeaders = (DefaultHttp2HeadersFrame) frame2;
+            respData = (DefaultHttp2DataFrame) frame1;
         }
+        assertEquals("200", respHeaders.headers().status().toString());
+        String content = respData.content().toString(StandardCharsets.UTF_8);
+        assertTrue(content.contains("Processed: jsonValue"));
     }
 
     @Test
@@ -212,8 +206,10 @@ class Http2HttpHandlerTest {
                     .when(mockChain)
                     .doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
             channel.writeInbound(headersFrame);
-
             Http2StreamFrame responseHeadersFrame = waitForHttp2Response(3000);
             assertNotNull(responseHeadersFrame);
             assertTrue(responseHeadersFrame instanceof 
DefaultHttp2HeadersFrame);
@@ -231,6 +227,9 @@ class Http2HttpHandlerTest {
                     .when(mockChain)
                     .doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
             Http2Headers headers = new DefaultHttp2Headers();
             headers.method("GET");
             headers.path("/test?param=onload=alert(1)");
@@ -255,6 +254,9 @@ class Http2HttpHandlerTest {
                     .when(mockChain)
                     .doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
             String maliciousJson = "{\"param\": 
\"<script>alert('xss')</script>\"}";
 
             Http2Headers headers = new DefaultHttp2Headers();
@@ -280,38 +282,34 @@ class Http2HttpHandlerTest {
 
     @Test
     void testHttp2PostRequestWithMultipleDataFrames() throws Exception {
-        try (MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class)) {
-            HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
-            doNothing().when(mockChain).doFilter(any());
-            
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-
-            Http2Headers headers = new DefaultHttp2Headers();
-            headers.method("POST");
-            headers.path("/test?param=multiFrame");
-
-            Http2HeadersFrame headersFrame = new 
DefaultHttp2HeadersFrame(headers, false);
-            channel.writeInbound(headersFrame);
+        HttpRequestFilterManager.initializeFilters();
 
-            String json1 = "{\"foo\":";
-            DefaultHttp2DataFrame dataFrame1 =
-                    new DefaultHttp2DataFrame(Unpooled.copiedBuffer(json1, 
StandardCharsets.UTF_8), false);
-            channel.writeInbound(dataFrame1);
-
-            String json2 = "\"bar\"}";
-            DefaultHttp2DataFrame dataFrame2 =
-                    new DefaultHttp2DataFrame(Unpooled.copiedBuffer(json2, 
StandardCharsets.UTF_8), true);
-            channel.writeInbound(dataFrame2);
-
-            Http2StreamFrame frame1 = null, frame2 = null;
-            long deadline = System.currentTimeMillis() + 5000;
-            while ((frame1 == null || frame2 == null) && 
System.currentTimeMillis() < deadline) {
-                if (frame1 == null) frame1 = channel.readOutbound();
-                if (frame2 == null) frame2 = channel.readOutbound();
-                if (frame1 == null || frame2 == null) Thread.sleep(500);
-            }
-            assertNotNull(frame1);
-            assertNotNull(frame2);
+        Http2Headers headers = new DefaultHttp2Headers();
+        headers.method("POST");
+        headers.path("/test?param=multiFrame");
+
+        Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(headers, 
false);
+        channel.writeInbound(headersFrame);
+
+        String json1 = "{\"foo\":";
+        DefaultHttp2DataFrame dataFrame1 =
+                new DefaultHttp2DataFrame(Unpooled.copiedBuffer(json1, 
StandardCharsets.UTF_8), false);
+        channel.writeInbound(dataFrame1);
+
+        String json2 = "\"bar\"}";
+        DefaultHttp2DataFrame dataFrame2 =
+                new DefaultHttp2DataFrame(Unpooled.copiedBuffer(json2, 
StandardCharsets.UTF_8), true);
+        channel.writeInbound(dataFrame2);
+
+        Http2StreamFrame frame1 = null, frame2 = null;
+        long deadline = System.currentTimeMillis() + 5000;
+        while ((frame1 == null || frame2 == null) && 
System.currentTimeMillis() < deadline) {
+            if (frame1 == null) frame1 = channel.readOutbound();
+            if (frame2 == null) frame2 = channel.readOutbound();
+            if (frame1 == null || frame2 == null) Thread.sleep(500);
         }
+        assertNotNull(frame1);
+        assertNotNull(frame2);
     }
 
     @Test
@@ -373,5 +371,8 @@ class Http2HttpHandlerTest {
         field.setAccessible(true);
         Map<String, HttpInvocation> map = (Map<String, HttpInvocation>) 
field.get(null);
         map.clear();
+        Field field2 = 
HttpRequestFilterManager.class.getDeclaredField("initialized");
+        field2.setAccessible(true);
+        field2.set(null, false);
     }
 }
diff --git 
a/core/src/test/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandlerTest.java
 
b/core/src/test/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandlerTest.java
index 8f41cc06b7..de5ef2f198 100644
--- 
a/core/src/test/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandlerTest.java
+++ 
b/core/src/test/java/org/apache/seata/core/rpc/netty/http/HttpDispatchHandlerTest.java
@@ -26,6 +26,7 @@ import io.netty.handler.codec.http.HttpVersion;
 import org.apache.seata.core.exception.HttpRequestFilterException;
 import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterChain;
 import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterManager;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
@@ -56,13 +57,9 @@ class HttpDispatchHandlerTest {
     }
 
     @BeforeEach
-    void setUp() {
+    void setUp() throws NoSuchMethodException {
         handler = new HttpDispatchHandler();
         channel = new EmbeddedChannel(handler);
-    }
-
-    @Test
-    void testGetRequestWithParameters() throws Exception {
         Method method = TestController.class.getMethod("handleRequest", 
String.class);
         ParamMetaData paramMetaData = new ParamMetaData();
         
paramMetaData.setParamConvertType(ParamMetaData.ParamConvertType.REQUEST_PARAM);
@@ -76,11 +73,22 @@ class HttpDispatchHandlerTest {
         invocation.setParamMetaData(paramMetaDatas);
 
         ControllerManager.addHttpInvocation(invocation);
+    }
+
+    @AfterEach
+    void after() throws Exception {
+        clearControllerManager();
+        Field field2 = 
HttpRequestFilterManager.class.getDeclaredField("initialized");
+        field2.setAccessible(true);
+        field2.set(null, false);
+    }
+
+    @Test
+    void testGetRequestWithParameters() throws Exception {
+
+        HttpRequestFilterManager.initializeFilters();
+        try {
 
-        try (MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class)) {
-            HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
-            doNothing().when(mockChain).doFilter(any());
-            
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
             HttpRequest request =
                     new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, 
HttpMethod.GET, "/test?param=testValue");
 
@@ -136,9 +144,9 @@ class HttpDispatchHandlerTest {
 
         MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class);
         
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockFilterChain);
-
+        mockedStatic.when(() -> 
HttpRequestFilterManager.getFilterChain(any())).thenReturn(mockFilterChain);
         try {
-            HttpRequest request = new 
DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/any");
+            HttpRequest request = new 
DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/test");
 
             channel.writeInbound(request);
 
@@ -157,7 +165,9 @@ class HttpDispatchHandlerTest {
                     .when(mockChain)
                     .doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
             HttpRequest request = new DefaultFullHttpRequest(
                     HttpVersion.HTTP_1_1, HttpMethod.GET, 
"/test?param=<script>alert(1)</script>");
 
@@ -175,7 +185,9 @@ class HttpDispatchHandlerTest {
                     .when(mockChain)
                     .doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
             HttpRequest request = new DefaultFullHttpRequest(
                     HttpVersion.HTTP_1_1, HttpMethod.GET, 
"/test?param=javascript:alert('XSS')");
 
@@ -193,7 +205,9 @@ class HttpDispatchHandlerTest {
                     .when(mockChain)
                     .doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
             HttpRequest request =
                     new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, 
HttpMethod.GET, "/test?param=onload=alert(1)");
 
@@ -218,11 +232,8 @@ class HttpDispatchHandlerTest {
         invocation.setParamMetaData(paramMetaDatas);
 
         ControllerManager.addHttpInvocation(invocation);
-
-        try (MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class)) {
-            HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
-            doNothing().when(mockChain).doFilter(any());
-            
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
+        HttpRequestFilterManager.initializeFilters();
+        try {
 
             String body = "param=postValue";
             DefaultFullHttpRequest request = new DefaultFullHttpRequest(
@@ -259,11 +270,8 @@ class HttpDispatchHandlerTest {
         invocation.setParamMetaData(paramMetaDatas);
 
         ControllerManager.addHttpInvocation(invocation);
-
-        try (MockedStatic<HttpRequestFilterManager> mockedStatic = 
mockStatic(HttpRequestFilterManager.class)) {
-            HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
-            doNothing().when(mockChain).doFilter(any());
-            
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
+        HttpRequestFilterManager.initializeFilters();
+        try {
 
             HttpRequest request =
                     new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, 
HttpMethod.GET, "/testClose?param=closeValue");
@@ -284,8 +292,10 @@ class HttpDispatchHandlerTest {
             HttpRequestFilterChain mockChain = 
mock(HttpRequestFilterChain.class);
             doThrow(new RuntimeException("Unexpected 
error")).when(mockChain).doFilter(any());
             
mockedStatic.when(HttpRequestFilterManager::getFilterChain).thenReturn(mockChain);
-
-            HttpRequest request = new 
DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/any");
+            mockedStatic
+                    .when(() -> HttpRequestFilterManager.getFilterChain(any()))
+                    .thenReturn(mockChain);
+            HttpRequest request = new 
DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/test");
 
             channel.writeInbound(request);
 
diff --git 
a/server/src/main/java/org/apache/seata/server/config/SeataNamingserverWebConfig.java
 
b/server/src/main/java/org/apache/seata/server/config/SeataNamingserverWebConfig.java
deleted file mode 100644
index ca85b8359d..0000000000
--- 
a/server/src/main/java/org/apache/seata/server/config/SeataNamingserverWebConfig.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-package org.apache.seata.server.config;
-
-import org.apache.seata.server.filter.RaftCondition;
-import org.apache.seata.server.filter.RaftRequestFilter;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Conditional;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.DependsOn;
-
-@Configuration
-public class SeataNamingserverWebConfig {
-
-    @Bean
-    @Conditional(RaftCondition.class)
-    @DependsOn("raftRequestFilter")
-    public FilterRegistrationBean<RaftRequestFilter> 
raftRequestServletFilter(RaftRequestFilter raftRequestFilter) {
-        FilterRegistrationBean<RaftRequestFilter> registrationBean = new 
FilterRegistrationBean<>();
-        registrationBean.setFilter(raftRequestFilter);
-        registrationBean.addUrlPatterns("/api/v1/console/*", "/vgroup/v1/*");
-        return registrationBean;
-    }
-}
diff --git 
a/server/src/main/java/org/apache/seata/server/filter/RaftRequestFilter.java 
b/server/src/main/java/org/apache/seata/server/filter/RaftRequestFilter.java
index 10d5ae6c2f..24d24544a5 100644
--- a/server/src/main/java/org/apache/seata/server/filter/RaftRequestFilter.java
+++ b/server/src/main/java/org/apache/seata/server/filter/RaftRequestFilter.java
@@ -16,27 +16,23 @@
  */
 package org.apache.seata.server.filter;
 
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http2.Http2Headers;
+import org.apache.seata.common.loader.LoadLevel;
 import org.apache.seata.common.store.SessionMode;
 import org.apache.seata.common.util.StringUtils;
-import org.apache.seata.core.exception.TransactionException;
-import org.apache.seata.core.exception.TransactionExceptionCode;
+import org.apache.seata.core.exception.HttpRequestFilterException;
+import org.apache.seata.core.rpc.netty.http.SimpleHttp2Request;
+import org.apache.seata.core.rpc.netty.http.filter.HttpFilterContext;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilter;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterChain;
 import org.apache.seata.server.cluster.listener.ClusterChangeEvent;
 import org.apache.seata.server.cluster.raft.context.SeataClusterContext;
-import org.apache.seata.server.console.exception.ConsoleException;
 import org.apache.seata.server.store.StoreConfig;
 import org.springframework.context.ApplicationListener;
-import org.springframework.context.annotation.Conditional;
-import org.springframework.http.HttpMethod;
 import org.springframework.stereotype.Component;
 
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
@@ -44,52 +40,75 @@ import java.util.concurrent.ConcurrentHashMap;
 import static org.apache.seata.common.Constants.RAFT_GROUP_HEADER;
 
 /**
- * Raft Leader Write Filter
+ * Raft Leader Write Filter for HTTP requests
  */
+@LoadLevel(name = "RaftRequest", order = 1)
 @Component
-@Conditional(RaftCondition.class)
-public class RaftRequestFilter implements Filter, 
ApplicationListener<ClusterChangeEvent> {
+public class RaftRequestFilter implements HttpRequestFilter, 
ApplicationListener<ClusterChangeEvent> {
 
     private static final Map<String, Boolean> GROUP_PREVENT = new 
ConcurrentHashMap<>();
 
     @Override
-    public void init(FilterConfig filterConfig) throws ServletException {}
-
-    @Override
-    public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain)
-            throws IOException, ServletException {
-        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
-        String group = httpRequest.getParameter("unit");
-        if (StringUtils.isBlank(group)) {
-            group = httpRequest.getHeader(RAFT_GROUP_HEADER);
+    public void doFilter(HttpFilterContext<?> context, HttpRequestFilterChain 
chain) throws HttpRequestFilterException {
+        String uri = getUri(context);
+        if (!isTargetUri(uri)) {
+            chain.doFilter(context);
+            return;
         }
+        String group = getGroup(context);
         if (group != null) {
             SeataClusterContext.bindGroup(group);
         }
         try {
-            String method = httpRequest.getMethod();
-            if (!HttpMethod.GET.name().equalsIgnoreCase(method)) {
+            String method;
+            if (context.getRequest() instanceof SimpleHttp2Request) {
+                SimpleHttp2Request request = (SimpleHttp2Request) 
context.getRequest();
+                method = request.getMethod().name();
+            } else {
+                HttpRequest request = (HttpRequest) context.getRequest();
+                method = request.method().name();
+            }
+            if (!"GET".equalsIgnoreCase(method)) {
                 if (!isPass(group)) {
-                    throw new ConsoleException(
-                            new TransactionException(
-                                    TransactionExceptionCode.NotRaftLeader,
-                                    " The current TC is not a leader node, 
interrupt processing of transactions!"),
-                            " The current TC is not a leader node, interrupt 
processing of transactions!");
+                    throw new HttpRequestFilterException(
+                            "The current TC is not a leader node, interrupt 
processing of transactions!");
                 }
             }
-            filterChain.doFilter(servletRequest, servletResponse);
+            chain.doFilter(context);
         } finally {
             SeataClusterContext.unbindGroup();
         }
     }
 
+    private String getGroup(HttpFilterContext<?> context) {
+        // Try to get from query params
+        Map<String, List<String>> params = 
context.getParamWrapper().getAllParamsAsMultiMap();
+        List<String> unitParams = params.get("unit");
+        if (unitParams != null && !unitParams.isEmpty()) {
+            return unitParams.get(0);
+        }
+        // Try to get the group header from HttpRequest or SimpleHttp2Request
+        if (context.getRequest() instanceof 
io.netty.handler.codec.http.HttpRequest) {
+            io.netty.handler.codec.http.HttpRequest httpRequest =
+                    (io.netty.handler.codec.http.HttpRequest) 
context.getRequest();
+            return httpRequest.headers().get(RAFT_GROUP_HEADER);
+        } else if (context.getRequest() instanceof SimpleHttp2Request) {
+            Http2Headers http2Headers = ((SimpleHttp2Request) 
context.getRequest()).getHeaders();
+            CharSequence headerValue = http2Headers.get(RAFT_GROUP_HEADER);
+            return headerValue != null ? headerValue.toString() : null;
+        }
+        return null;
+    }
+
     @Override
-    public void onApplicationEvent(ClusterChangeEvent event) {
-        setPrevent(event.getGroup(), event.isLeader());
+    public boolean shouldApply() {
+        return StoreConfig.getSessionMode() == SessionMode.RAFT;
     }
 
     @Override
-    public void destroy() {}
+    public void onApplicationEvent(ClusterChangeEvent event) {
+        setPrevent(event.getGroup(), event.isLeader());
+    }
 
     public static void setPrevent(String group, boolean prevent) {
         if (StoreConfig.getSessionMode() == SessionMode.RAFT) {
@@ -101,4 +120,23 @@ public class RaftRequestFilter implements Filter, 
ApplicationListener<ClusterCha
         // Non-raft mode always allows requests
         return Optional.ofNullable(GROUP_PREVENT.get(group)).orElse(false);
     }
+
+    private String getUri(HttpFilterContext<?> context) {
+        // Extract URI from HttpRequest or path from SimpleHttp2Request
+        if (context.getRequest() instanceof 
io.netty.handler.codec.http.HttpRequest) {
+            io.netty.handler.codec.http.HttpRequest httpRequest =
+                    (io.netty.handler.codec.http.HttpRequest) 
context.getRequest();
+            return httpRequest.uri();
+        } else if (context.getRequest() instanceof SimpleHttp2Request) {
+            return ((SimpleHttp2Request) context.getRequest()).getPath();
+        }
+        return null;
+    }
+
+    private boolean isTargetUri(String uri) {
+        if (StringUtils.isBlank(uri)) {
+            return false;
+        }
+        return uri.startsWith("/api/v1/console/") || 
uri.startsWith("/vgroup/v1/");
+    }
 }
diff --git 
a/server/src/main/java/org/apache/seata/server/filter/XSSHttpRequestFilter.java 
b/server/src/main/java/org/apache/seata/server/filter/XSSHttpRequestFilter.java
index baaee393af..9839fdcc7f 100644
--- 
a/server/src/main/java/org/apache/seata/server/filter/XSSHttpRequestFilter.java
+++ 
b/server/src/main/java/org/apache/seata/server/filter/XSSHttpRequestFilter.java
@@ -27,6 +27,7 @@ import org.apache.seata.config.ConfigurationFactory;
 import org.apache.seata.core.exception.HttpRequestFilterException;
 import org.apache.seata.core.rpc.netty.http.filter.HttpFilterContext;
 import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilter;
+import org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilterChain;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -43,7 +44,7 @@ import static 
org.apache.seata.common.DefaultValues.DEFAULT_XSS_KEYWORDS;
 /**
  * Filter to detect and block potential XSS attack vectors in HTTP request 
parameters.
  */
-@LoadLevel(name = "XSS", order = 1)
+@LoadLevel(name = "XSS", order = Integer.MIN_VALUE)
 public class XSSHttpRequestFilter implements HttpRequestFilter {
     /**
      * The constant CONFIG.
@@ -95,14 +96,14 @@ public class XSSHttpRequestFilter implements 
HttpRequestFilter {
 
     @Override
     public int getOrder() {
-        return 1;
+        return Integer.MIN_VALUE;
     }
 
     /**
      * Checks all request parameters for XSS risks and throws if found.
      */
     @Override
-    public void doFilter(HttpFilterContext<?> context) throws 
HttpRequestFilterException {
+    public void doFilter(HttpFilterContext<?> context, HttpRequestFilterChain 
chain) throws HttpRequestFilterException {
         Map<String, List<String>> allParams = 
context.getParamWrapper().getAllParamsAsMultiMap();
         for (Map.Entry<String, List<String>> entry : allParams.entrySet()) {
             for (String value : entry.getValue()) {
@@ -112,6 +113,8 @@ public class XSSHttpRequestFilter implements 
HttpRequestFilter {
                 }
             }
         }
+        // Continue to next filter
+        chain.doFilter(context);
     }
 
     /**
diff --git 
a/server/src/main/resources/META-INF/services/org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilter
 
b/server/src/main/resources/META-INF/services/org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilter
index 09ff4f7e00..63ad553ffb 100644
--- 
a/server/src/main/resources/META-INF/services/org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilter
+++ 
b/server/src/main/resources/META-INF/services/org.apache.seata.core.rpc.netty.http.filter.HttpRequestFilter
@@ -14,4 +14,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-org.apache.seata.server.filter.XSSHttpRequestFilter
\ No newline at end of file
+org.apache.seata.server.filter.XSSHttpRequestFilter
+org.apache.seata.server.filter.RaftRequestFilter
\ No newline at end of file
diff --git 
a/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
 
b/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
index 478358783e..710b61e56b 100644
--- 
a/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
+++ 
b/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
@@ -239,7 +239,7 @@ class ClusterControllerTest extends BaseSpringBootTest {
             }
         };
 
-        HttpClientUtil.doPostWithHttp2("http://127.0.0.1:"; + port + "/random", 
params, header, callback, 5000);
+        HttpClientUtil.doPostWithHttp2("http://127.0.0.1:"; + port + "/health", 
params, header, callback, 5000);
 
         assertTrue(latch.await(10, TimeUnit.SECONDS));
     }
@@ -274,7 +274,7 @@ class ClusterControllerTest extends BaseSpringBootTest {
             }
         };
 
-        HttpClientUtil.doPostWithHttp2("http://127.0.0.1:"; + port + "/random", 
jsonBody, header, callback, 5000);
+        HttpClientUtil.doPostWithHttp2("http://127.0.0.1:"; + port + "/health", 
jsonBody, header, callback, 5000);
 
         assertTrue(latch.await(10, TimeUnit.SECONDS));
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to