namespace Fengling.Console.Controllers;
///
/// 网关管理控制器
/// 提供网关服务、路由、集群实例等配置管理功能
///
[ApiController]
[Route("api/console/[controller]")]
[Authorize(AuthenticationSchemes = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)]
public class GatewayController(IGatewayService gatewayService, ILogger logger)
: ControllerBase
{
///
/// 获取网关统计数据
///
/// 网关的整体统计信息,包括请求量、响应时间等指标
/// 成功返回网关统计数据
/// 服务器内部错误
[HttpGet("statistics")]
[Produces("application/json")]
[ProducesResponseType(typeof(GatewayStatisticsDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task> GetStatistics()
{
try
{
var statistics = await gatewayService.GetStatisticsAsync();
return Ok(statistics);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting gateway statistics");
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 获取网关服务列表
///
/// 是否只返回全局服务,默认为false
/// 租户编码,用于筛选特定租户的服务
/// 网关服务列表,包含服务名称、地址、健康状态等信息
/// 成功返回网关服务列表
/// 服务器内部错误
[HttpGet("services")]
[Produces("application/json")]
[ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task>> GetServices(
[FromQuery] bool globalOnly = false,
[FromQuery] string? tenantCode = null)
{
try
{
var services = await gatewayService.GetServicesAsync(globalOnly, tenantCode);
return Ok(services);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting gateway services");
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 获取单个网关服务详情
///
/// 服务名称
/// 租户编码,用于筛选特定租户的服务
/// 网关服务的详细信息
/// 成功返回服务详情
/// 服务不存在
/// 服务器内部错误
[HttpGet("services/{serviceName}")]
[Produces("application/json")]
[ProducesResponseType(typeof(GatewayServiceDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task> GetService(
string serviceName,
[FromQuery] string? tenantCode = null)
{
try
{
var service = await gatewayService.GetServiceAsync(serviceName, tenantCode);
if (service == null)
{
return NotFound(new { message = $"Service {serviceName} not found" });
}
return Ok(service);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting service {ServiceName}", serviceName);
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 注册新的网关服务
///
/// 创建服务所需的配置信息
/// 创建的服务详情
/// 成功创建服务
/// 请求参数无效或服务已存在
/// 服务器内部错误
[HttpPost("services")]
[Produces("application/json")]
[ProducesResponseType(typeof(GatewayServiceDto), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task> RegisterService([FromBody] CreateGatewayServiceDto dto)
{
try
{
var service = await gatewayService.RegisterServiceAsync(dto);
return CreatedAtAction(nameof(GetService), new { serviceName = service.ServicePrefix }, service);
}
catch (InvalidOperationException ex)
{
logger.LogWarning(ex, "Validation error registering service");
return BadRequest(new { message = ex.Message });
}
catch (Exception ex)
{
logger.LogError(ex, "Error registering service");
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 注销网关服务
///
/// 要注销的服务名称
/// 租户编码,用于筛选特定租户的服务
/// 无内容响应
/// 成功注销服务
/// 服务不存在
/// 服务器内部错误
[HttpDelete("services/{serviceName}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task UnregisterService(
string serviceName,
[FromQuery] string? tenantCode = null)
{
try
{
var result = await gatewayService.UnregisterServiceAsync(serviceName, tenantCode);
if (!result)
{
return NotFound(new { message = $"Service {serviceName} not found" });
}
return Ok(new { message = "Service unregistered successfully" });
}
catch (Exception ex)
{
logger.LogError(ex, "Error unregistering service {ServiceName}", serviceName);
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 获取网关路由列表
///
/// 是否只返回全局路由,默认为false
/// 网关路由列表,包含路径匹配规则、转发目标等信息
/// 成功返回网关路由列表
/// 服务器内部错误
[HttpGet("routes")]
[Produces("application/json")]
[ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task>> GetRoutes([FromQuery] bool globalOnly = false)
{
try
{
var routes = await gatewayService.GetRoutesAsync(globalOnly);
return Ok(routes);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting gateway routes");
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 创建新的网关路由
///
/// 创建路由所需的配置信息
/// 创建的路由详情
/// 成功创建路由
/// 请求参数无效
/// 服务器内部错误
[HttpPost("routes")]
[Produces("application/json")]
[ProducesResponseType(typeof(GatewayRouteDto), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task> CreateRoute([FromBody] CreateGatewayRouteDto dto)
{
try
{
var route = await gatewayService.CreateRouteAsync(dto);
return Ok(route);
}
catch (InvalidOperationException ex)
{
return BadRequest(new { message = ex.Message });
}
catch (Exception ex)
{
logger.LogError(ex, "Error creating gateway route");
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 获取集群实例列表
///
/// 集群ID
/// 指定集群下的所有服务实例列表
/// 成功返回实例列表
/// 服务器内部错误
[HttpGet("clusters/{clusterId}/instances")]
[Produces("application/json")]
[ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task>> GetInstances(string clusterId)
{
try
{
var instances = await gatewayService.GetInstancesAsync(clusterId);
return Ok(instances);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting instances for cluster {ClusterId}", clusterId);
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 添加服务实例到集群
///
/// 创建实例所需的配置信息
/// 创建的实例详情
/// 成功添加实例
/// 请求参数无效
/// 服务器内部错误
[HttpPost("instances")]
[Produces("application/json")]
[ProducesResponseType(typeof(GatewayInstanceDto), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task> AddInstance([FromBody] CreateGatewayInstanceDto dto)
{
try
{
var instance = await gatewayService.AddInstanceAsync(dto);
return CreatedAtAction(nameof(GetInstances), new { clusterId = dto.ClusterId }, instance);
}
catch (InvalidOperationException ex)
{
return BadRequest(new { message = ex.Message });
}
catch (Exception ex)
{
logger.LogError(ex, "Error adding instance to cluster {ClusterId}", dto.ClusterId);
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 移除服务实例
///
/// 实例ID
/// 无内容响应
/// 成功移除实例
/// 实例不存在
/// 服务器内部错误
[HttpDelete("instances/{instanceId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task RemoveInstance(long instanceId)
{
try
{
var result = await gatewayService.RemoveInstanceAsync(instanceId);
if (!result)
{
return NotFound(new { message = $"Instance {instanceId} not found" });
}
return Ok(new { message = "Instance removed successfully" });
}
catch (Exception ex)
{
logger.LogError(ex, "Error removing instance {InstanceId}", instanceId);
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 更新实例权重
/// 用于负载均衡策略中调整实例的请求分发权重
///
/// 实例ID
/// 包含新权重值的请求体
/// 无内容响应
/// 成功更新权重
/// 实例不存在
/// 服务器内部错误
[HttpPut("instances/{instanceId}/weight")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task UpdateWeight(long instanceId, [FromBody] GatewayUpdateWeightDto dto)
{
try
{
var result = await gatewayService.UpdateInstanceWeightAsync(instanceId, dto.Weight);
if (!result)
{
return NotFound(new { message = $"Instance {instanceId} not found" });
}
return Ok(new { message = "Weight updated successfully" });
}
catch (Exception ex)
{
logger.LogError(ex, "Error updating weight for instance {InstanceId}", instanceId);
return StatusCode(500, new { message = ex.Message });
}
}
///
/// 重新加载网关配置
/// 触发网关重新加载所有配置,包括路由、服务、集群等配置
///
/// 无内容响应
/// 成功重新加载配置
/// 服务器内部错误
[HttpPost("reload")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task ReloadGateway()
{
try
{
await gatewayService.ReloadGatewayAsync();
return Ok(new { message = "Gateway configuration reloaded successfully" });
}
catch (Exception ex)
{
logger.LogError(ex, "Error reloading gateway configuration");
return StatusCode(500, new { message = ex.Message });
}
}
}