We are working on a dubbo gateway and need to support mutual access between different network clusters. This should be a common scenario. This requires dubbo to do two things for us:

1. Dynamically modify the ip and change the access of the local cluster to remote. This extension can be done, although there are some bugs, https://dubbo.apache.org/zh/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/

2. Forward the dubbo request. When the gateway receives the access request from cluster A, it should forward it to cluster B (now it returns an exception).

  From the code execution process.
  current:
  gateway-dubbo-provider receives the request -> parses -> judges whether the request interface has a corresponding cache URL -> no -> throws IOException -> netty returns

  ```java
  void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {
          Response res = new Response(req.getId(), req.getVersion());
          if (req.isBroken()) {
              Object data = req.getData();
              String msg;
              if (data == null) {
                  msg = null;
              } else if (data instanceof Throwable) {
                  msg = StringUtils.toString((Throwable) data);
              } else {
                  msg = data.toString();
              }
              res.setErrorMessage("Fail to decode request due to: " + msg);
              res.setStatus(Response.BAD_REQUEST);

              channel.send(res);
              return;
          }
  }
  ```

  ​

  expect:
  gateway-dubbo-provider receives the request -> parses -> judges whether the request interface has a corresponding cache URL -> no -> obtains the exception handler through spi (the request can be forwarded here) -> netty returns

```java
  void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {
          Response res = new Response(req.getId(), req.getVersion());
          if (req.isBroken()) {
              Object data = req.getData();
           //expert begin
          List<ExceptionHandler> list = spiExtensions.listByType(ExceptionHandler); 
          list.forEach(handler.handle(path,version))
           //expert end
              String msg;
              if (data == null) {
                  msg = null;
              } else if (data instanceof Throwable) {
                  msg = StringUtils.toString((Throwable) data);
              } else {
                  msg = data.toString();
              }
              res.setErrorMessage("Fail to decode request due to: " + msg);
              res.setStatus(Response.BAD_REQUEST);

              channel.send(res);
              return;
          }
  }
```


Since dubbo.extension provides dynamic ip replacement, then we should consider whether the target ip can be accepted and processed. I think this exception handler is an extension function of the dubbo.extension package.
We can provide ExceptionHandler similar to springboot, which can be more flexible

String REGISTRY_SEPARATOR = "|";
    Pattern REGISTRY_SPLIT_PATTERN = Pattern.compile("\\s*[|;]+\\s*");
    Pattern D_REGISTRY_SPLIT_PATTERN = Pattern.compile("\\s*[|]+\\s*");
    String SEMICOLON_SEPARATOR = ";";
    Pattern SEMICOLON_SPLIT_PATTERN = Pattern.compile("\\s*[;]+\\s*");
    Pattern EQUAL_SPLIT_PATTERN = Pattern.compile("\\s*[=]+\\s*");
    String DEFAULT_PROXY = "javassist";
    String DEFAULT_DIRECTORY = "dubbo";
    String PROTOCOL_KEY = "protocol";
    String DEFAULT_PROTOCOL = "dubbo";
    String DEFAULT_THREAD_NAME = "Dubbo";
    int DEFAULT_CORE_THREADS = 0;
    int DEFAULT_THREADS = 200;
    String EXECUTOR_SERVICE_COMPONENT_KEY = ExecutorService.class.getName();
    String CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY = "CONSUMER_SHARED_SERVICE_EXECUTOR";
    String INTERNAL_EXECUTOR_SERVICE_COMPONENT_KEY = "INTERNAL_SERVICE_EXECUTOR";
    String THREADPOOL_KEY = "threadpool";
    String THREAD_NAME_KEY = "threadname";
    String CORE_THREADS_KEY = "corethreads";
    String THREAD_POOL_EXHAUSTED_LISTENERS_KEY = "thread-pool-exhausted-listeners";
    String THREADS_KEY = "threads";
    String QUEUES_KEY = "queues";
    String ALIVE_KEY = "alive";
    String DEFAULT_THREADPOOL = "limited";
    String DEFAULT_CLIENT_THREADPOOL = "cached";
    String IO_THREADS_KEY = "iothreads";
    String KEEP_ALIVE_KEY = "keep.alive";
    int DEFAULT_QUEUES = 0;
    int DEFAULT_ALIVE = 60 * 1000;
    String TIMEOUT_KEY = "timeout";