Silky微服务框架在线文档Silky微服务框架在线文档
首页
文档
配置
源码解析
博文
github
gitee
  • 简体中文
  • English
首页
文档
配置
源码解析
博文
github
gitee
  • 简体中文
  • English
  • 启动时

    • 主机的构建
    • 服务引擎
    • 模块
    • 服务与服务条目的解析
    • Silky服务主机
    • 依赖注入约定
    • RPC 服务代理
  • 运行时

    • 终结点与路由
    • 执行器与调度
    • 本地执行器与服务端过滤器
    • 远程执行器与 RPC 调用
    • RPC 服务端消息处理
    • 服务治理
    • 缓存拦截器
    • 分布式事务(TCC)
    • HTTP 网关请求管道
    • 过滤器执行管道
    • Polly 弹性策略管道
    • 端点健康监控

概述

在 silky 框架的运行时,路由系统负责将外部 HTTP 请求或内部 RPC 调用映射到具体的服务条目(ServiceEntry)并执行。整个路由过程分为两个阶段:

  1. 启动时:根据服务应用接口(AppService)的方法定义,静态生成路由表
  2. 运行时:接收请求后,在路由表中查找匹配的服务条目并转发执行

路由模板的生成

ServiceRouteAttribute 与路由模板

每个服务应用接口都必须标注 [ServiceRoute] 特性,该特性指定了该接口下所有服务条目的路由前缀模板。

[AttributeUsage(AttributeTargets.Interface)]
public class ServiceRouteAttribute : Attribute, IRouteTemplateProvider
{
    // 默认模板:api/{appservice}
    public ServiceRouteAttribute() : this("api/{appservice}") { }

    public ServiceRouteAttribute(string template)
    {
        Template = template;
    }

    public string Template { get; }
}

默认路由模板为 api/{appservice},其中 {appservice} 是一个特殊占位符,框架会自动将其替换为应用服务接口的名称(去除 I 前缀和 AppService 后缀并转换为 kebab-case)。

例如 IOrderAppService → {appservice} = order,生成的路由前缀为 api/order。

可通过 {appservice=customName} 语法自定义名称:

[ServiceRoute("{appservice=orders}")]
public interface IOrderAppService { }
// 生成路由前缀:api/orders

也可以完全自定义路由前缀:

[ServiceRoute("v2/orders")]
public interface IOrderAppServiceV2 { }
// 生成路由前缀:v2/orders

路由段(Segment)类型

框架在解析路由模板时,将模板拆分为若干段(Segment),每个段属于以下三种类型之一:

类型枚举值说明示例
字面量SegmentType.Literal固定字符串,直接作为路由段api、v2、orders
应用服务名SegmentType.AppService{appservice} 或 {appservice=xxx} 占位符,框架替换为实际服务名{appservice} → order
路径参数SegmentType.Path{paramName} 形式,匹配 URL 中的动态值{id}、{id:long}

路径参数段支持类型约束(通过 : 分隔),例如 {id:long} 表示该路径参数必须能转换为 long 类型。


服务条目路由的完整生成规则

每个服务条目(接口方法)的完整路由 = 接口路由模板 + 方法路由段 + 路径参数段。

框架通过 TemplateHelper.GenerateServerEntryTemplate 完成最终模板的拼接,规则如下:

1. 方法显式指定了 HTTP 动词特性([HttpGet]、[HttpPost] 等)

若特性中同时指定了路由模板(如 [HttpGet("detail/{id}")]),则直接使用该模板拼接:

完整路由 = 接口前缀 / 特性指定的模板

若特性中未指定路由模板(如仅 [HttpGet]),则:

  • 启用 RESTful 风格(Governance:ApiIsRESTfulStyle = true,默认)时:

    • 自动去除方法名的 Async 后缀
    • 自动剥离 HTTP 动词约定前缀(见下表)
    • 自动追加路径参数段
  • 未启用 RESTful 风格时:

    • 使用完整方法名(去 Async 后缀)

HTTP 动词与方法名前缀的约定对应关系:

HTTP 方法自动剥离的方法名前缀
GETGetBy、GetFor、GetFrom、Get
POSTCreateOrUpdate、CreateOrModify、Create、Add
PUTCreateOrUpdate、CreateOrModify、Update、Put、Modify
PATCHCreateOrUpdate、CreateOrModify、Update、Put、Modify
DELETEDelete

示例:

[ServiceRoute]  // 模板:api/{appservice} → api/order
public interface IOrderAppService
{
    [HttpGet]
    Task<OrderDto> GetByIdAsync(long id);
    // 生成路由:GET api/order/{id}
    // 去 Async 后缀 → "GetById",剥离 "Get" 前缀 → "ById" → 简化为 "{id}"(路径参数)
    // 实际:GET api/order/{id}

    [HttpPost]
    Task<OrderDto> CreateAsync(CreateOrderInput input);
    // 生成路由:POST api/order
    // 去 Async → "Create",剥离 "Create" 前缀 → "" → 无方法段
    // POST api/order

    [HttpPut("{id}")]
    Task<OrderDto> UpdateAsync(long id, UpdateOrderInput input);
    // 生成路由:PUT api/order/{id}(直接使用特性指定的模板)

    [HttpDelete]
    Task DeleteAsync(long id);
    // 生成路由:DELETE api/order/{id}
}

2. 方法未指定 HTTP 动词特性(约定推断)

框架根据方法名前缀自动推断 HTTP 动词并生成路由,推断逻辑同上表。若方法名不匹配任何约定前缀,则默认映射为 POST。


运行时路由匹配

网关的路由匹配流程

外部 HTTP 请求进入 silky 网关后,路由匹配过程如下:

HTTP 请求
    │
    ▼
ASP.NET Core 路由中间件(UseRouting)
    │ 匹配已注册的 Endpoint
    ▼
SilkyRpcServiceEndpointDataSource(MapSilkyRpcServices 注册)
    │ 根据 Method + Path 定位 ServiceEntry
    ▼
服务条目查找(IServiceEntryLocator)
    │ 按 ServiceEntryId 或 WebAPI 路径定位
    ▼
本地执行 or RPC 远程调用
    │
    ▼
结果封装(ResponseWrapper)→ 返回 HTTP 响应

Endpoint 注册方式对比

silky 在 IEndpointRouteBuilder 上提供了多个扩展方法,用于注册不同场景的终结点:

方法用途
MapSilkyServiceEntries()注册 Web 主机自身提供的服务条目(用于有 HTTP 入口的业务微服务)
MapSilkyRpcServices()注册聚合所有 RPC 服务的路由(网关使用,转发至后端微服务)
MapSilkyTemplateServices()使用服务条目描述符注册(仅包含服务元信息,不执行实际调用)
MapSilkyDashboardServices()注册 Dashboard 管理端的路由

典型的网关 Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapSilkyRpcServices();       // 聚合所有微服务的 RPC 路由
    endpoints.MapSilkyDashboardServices(); // Dashboard 管理端
});

典型的 Web 主机(自身提供 HTTP 服务的业务微服务)Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapSilkyServiceEntries(); // 注册本服务的服务条目路由
});

路径参数的解析

路径参数在运行时通过 RoutePathHelper.ParserRouteParameters 解析:

// 路由模板:api/order/{id}
// 实际路径:api/order/42
// 解析结果:{ "id": "42" }

解析逻辑为按段对齐:逐段比对路由模板与实际路径,对 {...} 格式的模板段提取对应位置的路径值,拼装为参数字典后传入服务条目的执行器。

带约束的路径参数(如 {id:long}),约束名在参数名提取时被剥离(取 : 前的部分),约束校验发生在参数绑定阶段。


服务条目 Id 与路由的对应关系

服务条目 Id 是路由系统的另一个关键标识,其生成规则为:

服务条目 Id = 方法完全限定名 + "." + 参数名列表(下划线拼接)+ "_" + HTTP 动词

示例:

接口:Test.ITestAppService
方法:Task<string> Echo(string ping)
HTTP:GET

→ 服务条目 Id:Test.ITestAppService.Echo.ping_Get

该 Id 可以在以下场景中使用:

  • 通过 IInvokeTemplate 的 API 按 Id 调用远程服务,无需引用接口程序集
  • 在 Dashboard 管理端查询和管理服务条目
  • 链路追踪(SkyAPM)中标识具体的服务调用节点
编辑当前页
Next
执行器与调度