Gateway （本地网关）是 Solon 框架的特殊的 Handler 实现。它通过注册收集之后，在局部范围内提供：**二级路由**、**拦截**、**过滤**、**融断**、**异常处理**等功能，并统一到网关处理。


另一个作用：可以为同一批接口安排多个网关，进而定制不同的协议效果。


### 1、定义2个组件

**API_0**

```java
@Component(tag = "api")
public class API_0 {
    @Mapping
    public Result exec() {
        return Result.failure(404, "Interface does not exist");
    }
}
```

**API_hello_world**

```java
@Component(tag = "api")
public class API_hello_world {
    @Mapping("hello")
    public Result exec(String name) {
        return Result.succeed("Hello " + name);
    }
}
```

这2个组件，很特别？？？有@Mapping，看起来像控制器类。但它确用@Component注解，而且还有tag属性。

其实它们跟平常开发的控制器类是一样的。改用 @Component ，**是为了不被根路由器扫描进去**。而增加tag属性，是为了方便 Gateway 做局部扫描。

@Mapping 值为空时，会被 Gateway 做为默认接口对待。即找不到别的接口时，就用它。

### 2、定义 Gateway

**ApiGateway**

```java
@Mapping("/api/**")
@Component
public class ApiGateway extends Gateway {
    @Override
    protected void register() {
        addBeans(bw -> "api".equals(bw.tag()));
    }
}
```

最简单的 Gateway 只需要完成注册即可，输出效果跟普通的控制器差不多。启动服务后，我们就可以访问 `http://localhost:8080/api/hello`。


### 3、在 Gateway 上做点什么

加一个前置处理，做令牌验证。再重写渲染，对未处理异常做控制。

```java
@Mapping("/api/**")
@Component
public class ApiGateway extends Gateway {
    @Override
    protected void register() {

        //添加个前置处理
        filter((c, chain) -> {
            //检测有没有token（用 param 替代；方便手浏览器测试）
            if (c.param("t") == null) {
                //如果没有令牌；直接设定结果
                c.result = Result.failure(403, "Missing authentication information");

                //设为已处理（主接口就不会进去了）
                c.setHandled(true);
            }
            
            chain.doFilter(c);
        });

        //添加Bean
        addBeans(bw -> "api".equals(bw.tag()));
    }

    //重写渲染处理异常
    @Override
    public void render(Object obj, Context c) throws Throwable {
        if (obj instanceof Throwable) {
            c.render(Result.failure("unknown error"));
        } else {
            c.render(obj);
        }
    }
}
```




