ASP.NET Core MVC API 开发与调用规范文档

📋 文档概述

本文档记录了关于 ASP.NET Core MVC 中 API 控制器设计与客户端调用的详细讨论,包含参数绑定机制、安全最佳实践和多种客户端调用示例。

🏗️ 控制器架构

1. 基础控制器结构

namespace ddnsMainWeb.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class DnsHostController : ControllerBase
    {
        // 依赖注入
        private readonly JsaitContext _db;
        private readonly DnsApiService _dnsApiService;
        private readonly IConfiguration _configuration;
        private readonly ILogger<DnsHostController> _logger;

        // 构造函数
        public DnsHostController(
            JsaitContext db, 
            DnsApiService dnsApiService, 
            IConfiguration configuration,
            ILogger<DnsHostController> logger)
        {
            _db = db;
            _dnsApiService = dnsApiService;
            _configuration = configuration;
            _logger = logger;
        }
    }
}

2. 请求/响应模型

// 请求模型
public class GetHostIpRequest { public string host { get; set; } }
public class ScriptUpdateIpRequest { public string username { get; set; } public string password { get; set; } public string client_ip { get; set; } }
public class ClientUpdateIpRequest { public string Token { get; set; } public string client_ip { get; set; } }

// 统一响应模型
public class DnsHostResponse
{
    public bool success { get; set; }
    public string message { get; set; }
    public object data { get; set; }
}

🔐 API 安全设计

1. API Key 验证机制

// 在每个端点中验证 API Key
var apiKeyHeader = Request.Headers["X-Api-Key"].FirstOrDefault();
var expectedApiKey = _configuration["ClientConnectApi:ApiKey"];

if (string.IsNullOrEmpty(apiKeyHeader) || apiKeyHeader != expectedApiKey)
{
    return Unauthorized(new DnsHostResponse
    {
        success = false,
        message = "无效的API密钥"
    });
}

2. 参数验证策略

// 必填参数验证
if (string.IsNullOrEmpty(host))
{
    return BadRequest(new DnsHostResponse
    {
        success = false,
        message = "主机名不能为空"
    });
}

// IP 地址格式验证
if (!Tools.IsValidIp(request.client_ip))
{
    return BadRequest(new DnsHostResponse
    {
        success = false,
        message = "无效的IP地址格式"
    });
}

🌐 API 端点设计

1. GET /api/DnsHost/get-ip - 获取主机IP地址

功能: 根据主机名查询当前DNS记录

参数绑定方式对比:

方式 代码示例 绑定源 特点
显式绑定 [FromQuery] string host 仅查询字符串 安全、明确
隐式绑定 string host 多源自动绑定 灵活但有风险

推荐使用显式绑定:

[HttpGet("get-ip")]
public async Task<IActionResult> GetHostIp([FromQuery] string host)

2. POST /api/DnsHost/script-update-ip - 脚本更新IP

功能: 通过用户名密码验证更新DNS记录

[HttpPost("script-update-ip")]
public async Task<IActionResult> ScriptUpdateIp([FromBody] ScriptUpdateIpRequest request)

3. POST /api/DnsHost/client-update-ip - 客户端更新IP

功能: 通过Token验证更新DNS记录

[HttpPost("client-update-ip")]
public async Task<IActionResult> ClientUpdateIp([FromBody] ClientUpdateIpRequest request)

📡 客户端调用示例

1. C# HttpClient 调用

public async Task<DnsHostResponse> GetHostIpAsync(string host)
{
    _httpClient.DefaultRequestHeaders.Add("X-Api-Key", _apiKey);
    string url = $"/api/DnsHost/get-ip?host={Uri.EscapeDataString(host)}";
    var response = await _httpClient.GetAsync(url);
    // ... 处理响应
}

2. curl 命令行调用

curl -X GET "https://api.example.com/api/DnsHost/get-ip?host=example.com" \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json"

3. PowerShell 调用

$headers = @{
    "X-Api-Key" = $apiKey
    "Content-Type" = "application/json"
}
$response = Invoke-RestMethod -Uri $url -Method GET -Headers $headers

4. JavaScript/TypeScript 调用

const response = await fetch(apiUrl, {
    method: 'GET',
    headers: {
        'X-Api-Key': apiKey,
        'Content-Type': 'application/json'
    }
});

5. Python 调用

headers = {
    "X-Api-Key": api_key,
    "Content-Type": "application/json"
}
response = requests.get(url, headers=headers, params=params)

⚠️ 安全最佳实践

1. 参数绑定安全

  • 始终使用显式绑定 ([FromQuery], [FromBody], [FromRoute])
  • 避免隐式多源绑定,防止意外数据注入
  • 验证所有输入参数的来源和格式

2. API 密钥管理

  • 使用配置系统管理 API Key
  • 通过请求头传递 API Key
  • 实现统一的验证中间件

3. 错误处理

  • 使用统一的响应格式
  • 记录详细的错误日志
  • 不向客户端暴露敏感信息

4. 输入验证

// 多层级验证
if (string.IsNullOrEmpty(host)) // 空值检查
if (!Tools.IsValidIp(ip)) // 格式验证
if (host.Length > 255) // 长度限制
if (!Regex.IsMatch(host, @"^[a-zA-Z0-9.-]+$")) // 正则验证

🔄 参数绑定机制详解

ASP.NET Core 默认绑定顺序

  1. 查询字符串 (Query string)
  2. 路由值 (Route values)
  3. 表单数据 (Form data)
  4. 请求头 (Request headers)
  5. 请求体 (Request body)

显式绑定属性

  • [FromQuery] - 从查询字符串绑定
  • [FromRoute] - 从路由参数绑定
  • [FromForm] - 从表单数据绑定
  • [FromBody] - 从请求体绑定
  • [FromHeader] - 从请求头绑定

🛠️ 开发建议

1. 控制器设计原则

  • 每个控制器关注单一业务领域
  • 使用异步编程模式
  • 实现统一的异常处理
  • 记录关键操作日志

2. API 设计规范

  • RESTful 风格 URL 设计
  • 统一的响应格式
  • 适当的 HTTP 状态码
  • 版本化 API 端点

3. 性能优化

// 数据库查询优化
var dnsRecord = await _db.DnsRecords
    .Where(d => d.Hostname == host && d.Status == 1)
    .OrderByDescending(d => d.FreshDatetime)
    .FirstOrDefaultAsync(); // 使用 FirstOrDefaultAsync 而非 ToListAsync

// 及时释放资源
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
    // 数据库操作
}

📊 响应状态码规范

状态码 含义 使用场景
200 OK 请求成功 正常响应
400 Bad Request 请求参数错误 参数验证失败
401 Unauthorized 未授权 API Key 无效
404 Not Found 资源不存在 DNS 记录不存在
500 Internal Server Error 服务器内部错误 未处理的异常

🔍 调试与测试

1. 使用 Postman 测试

  • 方法: GET
  • URL: https://localhost:5001/api/DnsHost/get-ip?host=example.com
  • Headers:
  • X-Api-Key: your-api-key
  • Content-Type: application/json

2. 日志记录策略

// 信息级别日志
_logger.LogInformation($"DNS记录更新成功: {hostname} -> {ip}");

// 警告级别日志
_logger.LogWarning($"DNS记录更新失败: {hostname} - API返回失败");

// 错误级别日志
_logger.LogError(ex, $"DNS记录更新异常: {hostname} - {ex.Message}");

📝 总结要点

  1. 参数绑定:优先使用显式绑定 ([FromQuery]) 而非隐式绑定
  2. 安全第一:始终验证输入参数和 API 密钥
  3. 统一响应:使用标准化的响应格式
  4. 错误处理:实现全面的异常处理和日志记录
  5. 客户端兼容:提供多种客户端调用示例
  6. API 设计:遵循 RESTful 原则和 HTTP 语义

文档版本: 1.0
最后更新: $(date)
相关项目: ddnsMainWeb