TJC.Cyclops.Web.Core
2026.2.4.1
dotnet add package TJC.Cyclops.Web.Core --version 2026.2.4.1
NuGet\Install-Package TJC.Cyclops.Web.Core -Version 2026.2.4.1
<PackageReference Include="TJC.Cyclops.Web.Core" Version="2026.2.4.1" />
<PackageVersion Include="TJC.Cyclops.Web.Core" Version="2026.2.4.1" />
<PackageReference Include="TJC.Cyclops.Web.Core" />
paket add TJC.Cyclops.Web.Core --version 2026.2.4.1
#r "nuget: TJC.Cyclops.Web.Core, 2026.2.4.1"
#:package TJC.Cyclops.Web.Core@2026.2.4.1
#addin nuget:?package=TJC.Cyclops.Web.Core&version=2026.2.4.1
#tool nuget:?package=TJC.Cyclops.Web.Core&version=2026.2.4.1
Cyclops.Web.Core
项目概述
Cyclops.Web.Core是Cyclops.Framework框架中的Web核心组件,提供HTTP通信、Web服务构建、请求处理、响应格式化等基础功能。该组件为Web应用和API开发提供了统一的基础设施,包括中间件集合、HTTP客户端扩展、内容协商、错误处理、安全特性和Web工具集,简化了ASP.NET Core应用的开发和扩展。
核心功能模块
HTTP通信
- 增强型HTTP客户端
- 请求/响应拦截器
- 重试与超时策略
- HTTP内容处理
Web中间件
- 请求日志中间件
- 异常处理中间件
- CORS配置中间件
- 限流中间件
- 认证授权中间件
内容处理
- 自动内容协商
- 多格式序列化支持
- 文件上传处理
- 静态内容服务增强
路由与控制器
- 路由增强功能
- 控制器扩展方法
- 动作过滤器集合
- 模型绑定扩展
安全特性
- CSRF防护
- XSS防御
- CSP配置
- 安全头设置
高级功能
- API版本控制
- 健康检查集成
- 性能监控
- 分布式追踪
技术栈
- .NET 8.0
- ASP.NET Core
- Newtonsoft.Json / System.Text.Json
- Cyclops.Common
- Cyclops.Logging
环境依赖
- .NET 8.0 SDK
- ASP.NET Core Runtime
安装配置
NuGet安装
Install-Package Cyclops.Web.Core
基本配置
在应用程序启动时进行配置:
// 在Program.cs或Startup.cs中
using Cyclops.Web.Core;
var builder = WebApplication.CreateBuilder(args);
// 添加Cyclops.Web.Core服务
builder.Services.AddCyclopsWebCore(options => {
// HTTP客户端配置
options.HttpClientOptions = new HttpClientOptions {
DefaultTimeout = TimeSpan.FromSeconds(30),
EnableRetry = true,
MaxRetryCount = 3,
RetryDelay = TimeSpan.FromSeconds(1),
EnableCircuitBreaker = true,
CircuitBreakingThreshold = 5
};
// 序列化配置
options.SerializationOptions = new SerializationOptions {
DefaultSerializer = SerializerType.SystemTextJson,
EnableIndentation = builder.Environment.IsDevelopment(),
IgnoreNullValues = false
};
// 安全配置
options.SecurityOptions = new WebSecurityOptions {
EnableHsts = true,
EnableXContentTypeOptions = true,
EnableXFrameOptions = true,
EnableXXssProtection = true,
ContentSecurityPolicy = "default-src 'self'"
};
// API配置
options.ApiOptions = new ApiOptions {
EnableApiVersioning = true,
DefaultApiVersion = "1.0",
EnableProblemDetails = true
};
});
var app = builder.Build();
// 配置中间件
app.UseCyclopsWebCore();
// 应用程序配置
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
代码示例
增强型HTTP客户端示例
using Cyclops.Web.Core.Http;
using Microsoft.Extensions.DependencyInjection;
// HTTP客户端服务
public class EnhancedHttpClientService
{
private readonly IEnhancedHttpClientFactory _httpClientFactory;
public EnhancedHttpClientService(IEnhancedHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
// 创建并使用增强的HTTP客户端
public async Task<ApiResponse<T>> GetApiDataAsync<T>(string endpoint)
{
// 创建命名的HTTP客户端
var httpClient = _httpClientFactory.CreateClient("ApiClient");
try
{
// 设置基础地址(如果在配置中未设置)
httpClient.BaseAddress = new Uri("https://api.example.com/");
// 添加请求头
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
httpClient.DefaultRequestHeaders.Add("X-Client-Version", "1.0.0");
// 执行请求并自动处理序列化
var response = await httpClient.GetAsync<T>(endpoint,
successStatusCode: System.Net.HttpStatusCode.OK);
if (response.IsSuccess)
{
Console.WriteLine($"API请求成功,状态码: {response.StatusCode}");
return response;
}
else
{
Console.WriteLine($"API请求失败,状态码: {response.StatusCode}");
Console.WriteLine($"错误信息: {response.ErrorMessage}");
return response;
}
}
catch (HttpRequestException ex)
{
Console.WriteLine($"HTTP请求异常: {ex.Message}");
throw;
}
}
// 带请求拦截器的HTTP客户端
public async Task PostDataAsync<T>(string endpoint, T data)
{
// 创建配置了拦截器的HTTP客户端
var httpClient = _httpClientFactory.CreateClient("AuthenticatedClient", configure => {
// 添加请求拦截器(如添加认证令牌)
configure.AddRequestInterceptor(async (request) => {
// 模拟获取令牌
var token = await GetAuthTokenAsync();
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
Console.WriteLine($"请求被拦截,添加认证令牌: {request.RequestUri}");
return request;
});
// 添加响应拦截器
configure.AddResponseInterceptor(async (request, response) => {
Console.WriteLine($"响应被拦截: {request.RequestUri}, 状态码: {response.StatusCode}");
// 可以在这里处理特定响应
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine("认证失败,需要刷新令牌");
// 处理令牌刷新逻辑...
}
return response;
});
});
// 执行POST请求
var result = await httpClient.PostAsJsonAsync(endpoint, data);
await result.EnsureSuccessStatusCodeAsync();
Console.WriteLine("数据提交成功");
}
// 配置重试策略的HTTP客户端
public async Task GetDataWithRetryAsync(string endpoint)
{
var httpClient = _httpClientFactory.CreateClient("ResilientClient", configure => {
// 配置重试策略
configure.ConfigureRetry(retryOptions => {
retryOptions.RetryCount = 5;
retryOptions.RetryDelay = TimeSpan.FromSeconds(2);
retryOptions.MaxRetryDelay = TimeSpan.FromSeconds(30);
retryOptions.RetryBackoffMultiplier = 2;
// 配置重试条件
retryOptions.RetryConditions = new[] {
System.Net.HttpStatusCode.RequestTimeout,
System.Net.HttpStatusCode.ServiceUnavailable,
System.Net.HttpStatusCode.GatewayTimeout
};
// 配置重试回调
retryOptions.OnRetry = (attempt, delay, statusCode, exception) => {
Console.WriteLine($"请求失败,正在进行第 {attempt} 次重试,延迟: {delay.TotalSeconds}秒");
Console.WriteLine($"失败原因: {statusCode} - {exception?.Message}");
return Task.CompletedTask;
};
});
});
// 执行请求
var response = await httpClient.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine($"获取数据成功,内容长度: {content.Length} 字符");
}
// 模拟获取认证令牌
private async Task<string> GetAuthTokenAsync()
{
// 实际应用中应从认证服务获取令牌
await Task.Delay(10);
return "sample-auth-token-12345";
}
}
// API响应封装
public class ApiResponse<T>
{
public bool IsSuccess { get; set; }
public T Data { get; set; }
public System.Net.HttpStatusCode StatusCode { get; set; }
public string ErrorMessage { get; set; }
public IDictionary<string, string[]> ValidationErrors { get; set; }
}
中间件使用示例
using Cyclops.Web.Core.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
// 中间件配置扩展
public static class MiddlewareConfigurationExtensions
{
// 配置Cyclops中间件
public static IApplicationBuilder ConfigureCyclopsMiddleware(this IApplicationBuilder app)
{
// 使用请求日志中间件
app.UseRequestLogging(options => {
options.LogRequestHeaders = true;
options.LogResponseHeaders = false;
options.LogRequestBody = true;
options.LogResponseBody = false;
options.MaxBodyLogSize = 1024; // 最大记录1KB的请求体
options.ExcludePaths = new[] { "/health", "/metrics" };
options.LogLevel = LogLevel.Information;
});
// 使用异常处理中间件
app.UseExceptionHandling(options => {
options.ExceptionHandlers = new Dictionary<Type, Func<HttpContext, Exception, Task>> {
{
typeof(NotFoundException), async (context, ex) => {
context.Response.StatusCode = StatusCodes.Status404NotFound;
await context.Response.WriteJsonAsync(new {
error = "ResourceNotFound",
message = ex.Message,
timestamp = DateTime.UtcNow
});
}
},
{
typeof(ValidationException), async (context, ex) => {
context.Response.StatusCode = StatusCodes.Status400BadRequest;
var validationEx = ex as ValidationException;
await context.Response.WriteJsonAsync(new {
error = "ValidationError",
message = "请求参数验证失败",
details = validationEx?.Errors,
timestamp = DateTime.UtcNow
});
}
}
};
options.DefaultHandler = async (context, ex) => {
// 记录异常日志
var logger = context.RequestServices.GetRequiredService<ILogger<ExceptionHandlingMiddleware>>();
logger.LogError(ex, "未处理的异常: {Path}", context.Request.Path);
// 向客户端返回错误信息
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
await context.Response.WriteJsonAsync(new {
error = "InternalServerError",
message = "服务器内部错误",
timestamp = DateTime.UtcNow
});
};
});
// 使用CORS中间件
app.UseCorsPolicy(options => {
options.AllowOrigins = new[] { "https://example.com", "https://api.example.com" };
options.AllowMethods = new[] { "GET", "POST", "PUT", "DELETE", "OPTIONS" };
options.AllowHeaders = new[] { "Content-Type", "Authorization", "X-Requested-With" };
options.AllowCredentials = true;
options.MaxAge = TimeSpan.FromHours(1);
});
// 使用限流中间件
app.UseRateLimiting(options => {
options.Policies = new[] {
new RateLimitPolicy {
Name = "ApiRateLimit",
PathPattern = "/api/**",
Limit = 100, // 100个请求
Per = TimeSpan.FromMinutes(1), // 每分钟
ExcludePaths = new[] { "/api/health", "/api/public/**" },
LimitExceededHandler = async (context) => {
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context.Response.Headers["Retry-After"] = "60";
await context.Response.WriteJsonAsync(new {
error = "TooManyRequests",
message = "请求频率过高,请稍后再试",
retryAfter = 60
});
}
}
};
});
// 使用安全头中间件
app.UseSecurityHeaders(options => {
options.Headers = new[] {
new SecurityHeader { Name = "X-Content-Type-Options", Value = "nosniff" },
new SecurityHeader { Name = "X-Frame-Options", Value = "SAMEORIGIN" },
new SecurityHeader { Name = "X-XSS-Protection", Value = "1; mode=block" },
new SecurityHeader { Name = "Referrer-Policy", Value = "strict-origin-when-cross-origin" },
new SecurityHeader {
Name = "Content-Security-Policy",
Value = "default-src 'self'; script-src 'self' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"
}
};
});
return app;
}
}
// 自定义异常类型
public class NotFoundException : Exception
{
public NotFoundException(string message) : base(message) { }
}
public class ValidationException : Exception
{
public ValidationException(string message, IDictionary<string, string[]> errors = null) : base(message)
{
Errors = errors ?? new Dictionary<string, string[]>();
}
public IDictionary<string, string[]> Errors { get; }
}
控制器与API扩展示例
using Cyclops.Web.Core.Attributes;
using Cyclops.Web.Core.Controllers;
using Cyclops.Web.Core.Extensions;
using Microsoft.AspNetCore.Mvc;
// 基础控制器
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[Produces("application/json")]
[Consumes("application/json")]
public abstract class ApiControllerBase : ControllerBase
{
// 统一的成功响应
protected ActionResult<T> OkResponse<T>(T data, string message = null)
{
return Ok(new ApiResponse<T> {
Success = true,
Data = data,
Message = message,
Timestamp = DateTime.UtcNow
});
}
// 统一的错误响应
protected ActionResult ErrorResponse(string message, int statusCode = StatusCodes.Status400BadRequest, object details = null)
{
var errorResponse = new ErrorResponse {
Success = false,
Message = message,
Details = details,
Timestamp = DateTime.UtcNow
};
return StatusCode(statusCode, errorResponse);
}
// 获取当前用户ID
protected string GetCurrentUserId()
{
return User.FindFirstValue(ClaimTypes.NameIdentifier);
}
// 获取客户端IP地址
protected string GetClientIpAddress()
{
return HttpContext.Connection.RemoteIpAddress?.ToString();
}
}
// API响应模型
public class ApiResponse<T>
{
public bool Success { get; set; }
public T Data { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
}
public class ErrorResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public object Details { get; set; }
public DateTime Timestamp { get; set; }
}
// 具体控制器示例
public class ProductsController : ApiControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
[ProducesResponseType(typeof(ApiResponse<IEnumerable<ProductDto>>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult> GetProducts([FromQuery] ProductQuery query)
{
try
{
var products = await _productService.GetProductsAsync(query);
return OkResponse(products, $"成功获取 {products.Count()} 个产品");
}
catch (Exception ex)
{
return ErrorResponse("获取产品列表失败", StatusCodes.Status500InternalServerError);
}
}
[HttpGet("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<ProductDetailDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)]
public async Task<ActionResult> GetProductById(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
{
return ErrorResponse($"产品ID {id} 不存在", StatusCodes.Status404NotFound);
}
return OkResponse(product);
}
[HttpPost]
[Authorize(Roles = "Admin,ProductManager")]
[ValidateModel]
[ProducesResponseType(typeof(ApiResponse<ProductDto>), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status403Forbidden)]
public async Task<ActionResult> CreateProduct([FromBody] CreateProductDto request)
{
try
{
var product = await _productService.CreateProductAsync(request);
return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, OkResponse(product, "产品创建成功"));
}
catch (ValidationException ex)
{
return ErrorResponse("产品创建失败", StatusCodes.Status400BadRequest, ex.Errors);
}
}
}
// 自定义特性
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
// 转换验证错误为字典格式
var errors = context.ModelState
.Where(x => x.Value.Errors.Any())
.ToDictionary(
x => x.Key,
x => x.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
// 返回验证错误响应
context.Result = new BadRequestObjectResult(new ErrorResponse {
Success = false,
Message = "请求参数验证失败",
Details = errors,
Timestamp = DateTime.UtcNow
});
}
}
}
// 查询参数模型
public class ProductQuery
{
[FromQuery(Name = "category")]
public int? CategoryId { get; set; }
[FromQuery(Name = "min_price")]
[Range(0, double.MaxValue)]
public decimal? MinPrice { get; set; }
[FromQuery(Name = "max_price")]
[Range(0, double.MaxValue)]
public decimal? MaxPrice { get; set; }
[FromQuery(Name = "page")]
[Range(1, int.MaxValue)]
public int Page { get; set; } = 1;
[FromQuery(Name = "page_size")]
[Range(1, 100)]
public int PageSize { get; set; } = 20;
[FromQuery(Name = "sort")]
public string SortBy { get; set; } = "created_at";
[FromQuery(Name = "order")]
[AllowedValues("asc", "desc")]
public string SortOrder { get; set; } = "desc";
}
// DTO模型
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public class ProductDetailDto : ProductDto
{
public string Sku { get; set; }
public int StockQuantity { get; set; }
public string ImageUrl { get; set; }
public List<ProductAttributeDto> Attributes { get; set; }
}
public class CreateProductDto
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[StringLength(500)]
public string Description { get; set; }
[Required]
[Range(0.01, double.MaxValue)]
public decimal Price { get; set; }
[Required]
[Range(1, int.MaxValue)]
public int CategoryId { get; set; }
[Required]
[StringLength(50)]
public string Sku { get; set; }
[Range(0, int.MaxValue)]
public int StockQuantity { get; set; } = 0;
public List<ProductAttributeCreateDto> Attributes { get; set; }
}
public class ProductAttributeDto
{
public string Name { get; set; }
public string Value { get; set; }
}
public class ProductAttributeCreateDto
{
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(100)]
public string Value { get; set; }
}
内容处理与序列化示例
using Cyclops.Web.Core.Content;
using Cyclops.Web.Core.Serialization;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json.Serialization;
// 内容协商配置
public static class ContentNegotiationExtensions
{
public static IMvcBuilder ConfigureContentNegotiation(this IMvcBuilder mvcBuilder)
{
// 配置JSON序列化选项
mvcBuilder.AddJsonOptions(options => {
// 忽略循环引用
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
// 日期时间格式
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
// 添加自定义格式支持
mvcBuilder.AddFormatterMappings(mappings => {
mappings.SetMediaTypeMappingForFormat("xml", MediaTypeNames.Application.Xml);
mappings.SetMediaTypeMappingForFormat("json", MediaTypeNames.Application.Json);
mappings.SetMediaTypeMappingForFormat("csv", "text/csv");
mappings.SetMediaTypeMappingForFormat("pdf", "application/pdf");
});
// 自定义内容协商提供程序
mvcBuilder.ConfigureApiBehaviorOptions(options => {
options.InvalidModelStateResponseFactory = context => {
// 自定义验证错误响应
var result = new ValidationFailedResult(context.ModelState);
result.ContentTypes.Add(MediaTypeNames.Application.Json);
return result;
};
});
return mvcBuilder;
}
}
// 自定义验证结果
public class ValidationFailedResult : ObjectResult
{
public ValidationFailedResult(ModelStateDictionary modelState) :
base(new ValidationErrorResponse(modelState))
{
StatusCode = StatusCodes.Status400BadRequest;
}
}
// 验证错误响应
public class ValidationErrorResponse
{
public ValidationErrorResponse(ModelStateDictionary modelState)
{
Errors = modelState
.Where(e => e.Value.Errors.Count > 0)
.ToDictionary(
k => k.Key,
v => v.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
Success = false;
Message = "请求参数验证失败";
Timestamp = DateTime.UtcNow;
}
public bool Success { get; set; }
public string Message { get; set; }
public Dictionary<string, string[]> Errors { get; set; }
public DateTime Timestamp { get; set; }
}
// 自定义日期时间转换器
public class DateTimeConverter : JsonConverter<DateTime>
{
private readonly string _format = "yyyy-MM-ddTHH:mm:ss.fffZ";
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
if (DateTime.TryParseExact(reader.GetString(), _format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
{
return date;
}
}
return reader.GetDateTime();
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString(_format, CultureInfo.InvariantCulture));
}
}
// 自定义格式化器
public class CsvOutputFormatter : TextOutputFormatter
{
public CsvOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/csv"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
protected override bool CanWriteType(Type type)
{
return typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(string);
}
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
var data = context.Object as IEnumerable;
using (var writer = new StreamWriter(response.Body, selectedEncoding))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
// 处理泛型集合
var itemType = data.GetType().GetGenericArguments().FirstOrDefault();
if (itemType != null)
{
// 自动映射属性
csv.WriteHeader(itemType);
csv.NextRecord();
foreach (var record in data)
{
csv.WriteRecord(record);
csv.NextRecord();
}
}
return writer.FlushAsync();
}
}
}
API版本控制示例
using Cyclops.Web.Core.Versioning;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.AspNetCore.Mvc;
// API版本控制配置
public static class ApiVersioningExtensions
{
public static IServiceCollection ConfigureApiVersioning(this IServiceCollection services)
{
services.AddApiVersioning(options => {
// 使用URL路径参数作为版本控制方式
options.ApiVersionReader = new UrlSegmentApiVersionReader();
// 默认版本
options.DefaultApiVersion = new ApiVersion(1, 0);
// 允许隐式版本
options.AssumeDefaultVersionWhenUnspecified = true;
// 报告所有可用版本
options.ReportApiVersions = true;
// 版本控制错误响应
options.ErrorResponses = new CyclopsErrorResponseProvider();
});
// 添加API探索服务
services.AddVersionedApiExplorer(options => {
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
return services;
}
}
// 自定义错误响应提供程序
public class CyclopsErrorResponseProvider : IErrorResponseProvider
{
public IActionResult CreateErrorResponse(ErrorResponseContext context)
{
var errorResponse = new ErrorResponse {
Success = false,
Message = GetErrorMessageForError(context.ErrorCode),
Details = context.MessageDetail,
Timestamp = DateTime.UtcNow
};
return new ObjectResult(errorResponse) {
StatusCode = context.StatusCode
};
}
private string GetErrorMessageForError(string errorCode)
{
return errorCode switch {
"UnsupportedApiVersion" => "不支持的API版本",
"ApiVersionUnspecified" => "未指定API版本",
"InvalidApiVersion" => "无效的API版本格式",
"AmbiguousApiVersion" => "API版本不明确",
"NoRouteMatched" => "未找到匹配的路由",
_ => "API版本错误"
};
}
}
// 版本化控制器示例
[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ProductsV1Controller : ApiControllerBase
{
private readonly IProductService _productService;
public ProductsV1Controller(IProductService productService)
{
_productService = productService;
}
[HttpGet]
[ProducesResponseType(typeof(ApiResponse<IEnumerable<ProductDto>>), StatusCodes.Status200OK)]
public async Task<ActionResult> GetProducts([FromQuery] ProductQuery query)
{
var products = await _productService.GetProductsAsync(query);
return OkResponse(products);
}
}
// V2版本控制器(扩展V1)
[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("2.0")]
public class ProductsV2Controller : ApiControllerBase
{
private readonly IProductServiceV2 _productService;
public ProductsV2Controller(IProductServiceV2 productService)
{
_productService = productService;
}
[HttpGet]
[ProducesResponseType(typeof(ApiResponse<IEnumerable<ProductV2Dto>>), StatusCodes.Status200OK)]
public async Task<ActionResult> GetProducts([FromQuery] ProductV2Query query)
{
var products = await _productService.GetProductsAsync(query);
// V2版本的增强响应
return OkResponse(products, new {
Pagination = new {
Total = products.TotalCount,
Page = query.Page,
PageSize = query.PageSize,
Pages = products.PageCount
},
Filters = query.ToDictionary()
});
}
// V2版本新增的端点
[HttpGet("trending")]
[ProducesResponseType(typeof(ApiResponse<IEnumerable<ProductV2Dto>>), StatusCodes.Status200OK)]
public async Task<ActionResult> GetTrendingProducts([FromQuery] int limit = 10)
{
var products = await _productService.GetTrendingProductsAsync(limit);
return OkResponse(products, "获取热门产品成功");
}
}
版本信息
贡献者
- yswenli
许可证
保留所有权利
企服版框架接口返回结果规范
本文档明确企服版框架接口在不同场景下的返回结果规则,涵盖异常场景与正常场景,为接口开发及对接提供明确依据。
一、网络或服务器问题场景
当接口调用遇到网络故障或服务器异常时,不返回结构化数据,直接返回对应的HTTP状态码,具体规则如下:
返回HTTP状态码:500 或 404
说明:500通常表示服务器内部错误,404通常表示请求的接口路径不存在或资源未找到,此场景无额外响应体内容。
二、代码问题场景
当接口执行过程中出现未捕获取的代码异常,或主动抛出Exception时,返回带HTTP状态码500的结构化结果,具体规则如下:
返回HTTP状态码:500
响应体示例:
{
"code": 999,
"type": "Fail",
"message": "Server API error, please contact administrator support to resolve this issue.",
"result": null,
"extras": null,
"time": "2025-12-04 16:52:55.020"
}
说明:该场景为系统级错误,需开发人员排查代码逻辑或服务器配置问题,time字段为错误发生的具体时间戳。
三、业务异常场景
在代码中主动抛出throw FriendlyError.Ex(EnumErrorCode)时,返回HTTP状态码200的结构化业务异常结果,具体规则如下:
返回HTTP状态码:200
响应体示例:
{
"code": "200",
"type": "Fail",
"message": "[D1002] 记录不存在",
"result": null,
"extras": null,
"time": "2025-12-04 16:56:40"
}
说明:该场景为业务逻辑层面的异常,message字段中包含具体的错误码(如示例中的D1002)和错误描述,便于对接方定位业务问题,time字段为异常发生的具体时间戳。
四、正常响应场景
当接口调用成功并完成预期业务逻辑时,返回HTTP状态码200的结构化成功结果,具体规则如下:
返回HTTP状态码:200
响应体示例:
{
"code": "200",
"type": "Success",
"message": "OK",
"result": "Hello",
"extras": null,
"time": "2025-12-04 17:00:04"
}
说明:type字段固定为"Success",message字段固定为"OK",result字段为接口返回的具体业务数据(示例中为"Hello",实际场景根据接口功能返回对应数据结构),time字段为响应发生的具体时间戳。
(注:文档部分内容可能由 AI 生成)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Ben.Demystifier (>= 0.4.1)
- JWT.Standard (>= 2025.5.7.1)
- Lazy.Captcha.Core (>= 2.2.2)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 8.0.0)
- Microsoft.AspNetCore.OpenApi (>= 8.0.15)
- Microsoft.AspNetCore.SignalR.Client (>= 9.0.4)
- Microsoft.Extensions.Hosting.Systemd (>= 10.0.2)
- Microsoft.Extensions.Hosting.WindowsServices (>= 10.0.2)
- Microsoft.Extensions.Http (>= 10.0.2)
- Microsoft.IdentityModel.Tokens (>= 7.0.3)
- Microsoft.VisualStudio.Azure.Containers.Tools.Targets (>= 1.23.0)
- nacos-sdk-csharp (>= 1.3.10)
- nacos-sdk-csharp.AspNetCore (>= 1.3.10)
- nacos-sdk-csharp.Extensions.Configuration (>= 1.3.10)
- SkiaSharp.NativeAssets.Linux.NoDependencies (>= 3.119.1)
- SKIT.FlurlHttpClient.Wechat.TenpayV3 (>= 3.16.0)
- SqlSugarCore (>= 5.1.4.211)
- Swashbuckle.AspNetCore (>= 9.0.1)
- Swashbuckle.AspNetCore.Newtonsoft (>= 9.0.1)
- TJC.Cyclops.ApprovalFlow (>= 2026.2.4.1)
- TJC.Cyclops.CloudStorage (>= 2026.2.4.1)
- TJC.Cyclops.Common (>= 2026.2.4.1)
- TJC.Cyclops.LogLib (>= 2026.2.4.1)
- TJC.Cyclops.Orm (>= 2026.2.4.1)
- TJC.Cyclops.Redis (>= 2026.2.4.1)
- TJC.Cyclops.Service (>= 2026.2.4.1)
- TJC.Cyclops.Speech (>= 2026.2.4.1)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on TJC.Cyclops.Web.Core:
| Package | Downloads |
|---|---|
|
TJC.Cyclops.Wechat
企服版框架中微信对接相关业务核心项目 |
|
|
TJC.Cyclops.TaskSystem
企服版任务核心 |
|
|
TJC.Cyclops.UCenter
企服版框架中Discuz的UCenter用户同步注册、登录 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.2.4.1 | 110 | 2/4/2026 |
| 2026.1.15.1 | 120 | 1/15/2026 |
| 2026.1.14.2 | 116 | 1/14/2026 |
| 2026.1.14.1 | 107 | 1/14/2026 |
| 2026.1.13.2 | 115 | 1/13/2026 |
| 2026.1.13.1 | 131 | 1/13/2026 |
| 2026.1.7.1 | 134 | 1/7/2026 |
| 2025.12.23.1 | 219 | 12/23/2025 |
| 2025.12.16.1 | 319 | 12/16/2025 |
| 2025.12.15.2 | 268 | 12/15/2025 |
| 2025.12.15.1 | 299 | 12/15/2025 |
| 2025.12.12.1 | 173 | 12/12/2025 |
| 2025.12.11.1 | 471 | 12/11/2025 |
| 2025.12.4.1 | 233 | 12/4/2025 |
| 2025.12.3.3 | 734 | 12/3/2025 |
| 2025.12.3.2 | 712 | 12/3/2025 |
| 2025.12.3.1 | 703 | 12/3/2025 |
| 2025.12.2.1 | 719 | 12/2/2025 |
| 2025.11.28.1 | 221 | 11/28/2025 |
| 2025.11.25.1 | 234 | 11/25/2025 |
企服版框架中api核心功能项目,基于aspnetcore集成di、jwt、swagger、codefirtst、支持多种常见数据库、nacos配置中心、统一接口回复参数、全局异常捕获、全局接口日志、防重放攻击、图形验证码、快捷上下文对象、上传下载、数据导入导出等功能