Web API基础

一、架构设计与原理

Web API[基于HTTP协议],遵循RESTful设计原则。它将应用程序的业务功能通过统一的接口暴露给客户端,实现前后端分离的架构模式。

客户端

HTTP请求

路由系统

控制器

业务逻辑

数据访问

数据库

JSON响应

二、控制器开发详解

控制器是Web API的核心组件,负责处理HTTP请求并返回响应。使用 [ApiController] 特性可以启用API相关的行为增强。

csharp 复制代码
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;
    
    public ProductsController(IProductService productService)
    {
        _productService = productService; // 依赖注入
    }

    // GET: api/products - 获取所有产品
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
    {
        try
        {
            var products = await _productService.GetAllAsync();
            return Ok(products);
        }
        catch (Exception ex)
        {
            return StatusCode(500, new { message = "获取产品失败", error = ex.Message });
        }
    }

    // GET: api/products/5 - 根据ID获取产品
    [HttpGet("{id:int}")]
    public async Task<ActionResult<Product>> GetProduct(int id)
    {
        if (id <= 0)
            return BadRequest("产品ID必须大于0");

        var product = await _productService.GetByIdAsync(id);
        return product == null ? NotFound($"未找到ID为{id}的产品") : Ok(product);
    }

    // POST: api/products - 创建新产品
    [HttpPost]
    public async Task<ActionResult<Product>> CreateProduct([FromBody] CreateProductDto productDto)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        var product = await _productService.CreateAsync(productDto);
        return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);
    }

    // PUT: api/products/5 - 更新产品
    [HttpPut("{id:int}")]
    public async Task<IActionResult> UpdateProduct(int id, [FromBody] UpdateProductDto productDto)
    {
        if (id != productDto.Id)
            return BadRequest("路径ID与请求体ID不匹配");

        var updated = await _productService.UpdateAsync(productDto);
        return updated ? NoContent() : NotFound();
    }

    // DELETE: api/products/5 - 删除产品
    [HttpDelete("{id:int}")]
    public async Task<IActionResult> DeleteProduct(int id)
    {
        var deleted = await _productService.DeleteAsync(id);
        return deleted ? NoContent() : NotFound();
    }
}

AI写代码csharp
运行
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667

三、HTTP动词与RESTful设计

RESTful API使用HTTP动词表示不同的操作类型,每个动词都有特定的语义和用途:

GET

获取资源

POST

创建资源

PUT

完整更新

PATCH

部分更新

DELETE

删除资源

最佳实践:

  • GET:幂等且安全,用于查询数据
  • POST:非幂等,用于创建资源
  • PUT:幂等,用于完整替换资源
  • DELETE:幂等,用于删除资源

四、路由配置与参数绑定

ASP.NET Core提供了灵活的路由系统,支持多种参数绑定方式:

csharp 复制代码
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    // 路由约束示例
    [HttpGet("{id:int:min(1)}")]        // 整数且最小值为1
    [HttpGet("name/{name:alpha}")]      // 仅字母
    [HttpGet("page/{page:int:range(1,100)}")]  // 范围约束

    // 复杂参数绑定
    [HttpGet("search")]
    public IActionResult SearchUsers(
        [FromQuery] string keyword,         // 查询字符串参数
        [FromQuery] int page = 1,          // 带默认值
        [FromQuery] int pageSize = 10,
        [FromHeader] string userAgent = "") // 请求头参数
    {
        var users = SearchUsers(keyword, page, pageSize);
        return Ok(new 
        { 
            data = users,
            pagination = new { page, pageSize, total = users.Count() },
            userAgent
        });
    }

    // 复杂对象绑定
    [HttpPost("register")]
    public async Task<IActionResult> Register(
        [FromBody] UserRegisterDto request,    // JSON请求体
        [FromServices] IUserService userService) // 服务注入
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        var result = await userService.RegisterAsync(request);
        return result.Success ? Ok(result) : BadRequest(result.Errors);
    }
}

AI写代码csharp
运行
123456789101112131415161718192021222324252627282930313233343536373839

五、数据验证与错误处理

数据验证是API安全性和稳定性的重要保障:

csharp 复制代码
// 数据传输对象 (DTO)
public class CreateProductDto
{
    [Required(ErrorMessage = "产品名称不能为空")]
    [StringLength(100, MinimumLength = 2, ErrorMessage = "产品名称长度应在2-100字符之间")]
    public string Name { get; set; }

    [Required]
    [Range(0.01, double.MaxValue, ErrorMessage = "价格必须大于0")]
    public decimal Price { get; set; }

    [StringLength(500, ErrorMessage = "描述长度不能超过500字符")]
    public string Description { get; set; }

    [EmailAddress(ErrorMessage = "邮箱格式不正确")]
    public string ContactEmail { get; set; }
}

// 全局异常处理中间件
public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;

    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理请求时发生未处理的异常");
            await HandleExceptionAsync(context, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        
        var response = exception switch
        {
            ArgumentException => new { StatusCode = 400, Message = "参数错误", Details = exception.Message },
            KeyNotFoundException => new { StatusCode = 404, Message = "资源未找到" },
            UnauthorizedAccessException => new { StatusCode = 401, Message = "未授权访问" },
            _ => new { StatusCode = 500, Message = "服务器内部错误" }
        };

        context.Response.StatusCode = response.StatusCode;
        await context.Response.WriteAsync(JsonSerializer.Serialize(response));
    }
}

AI写代码csharp
运行
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859

六、状态码最佳实践

正确使用HTTP状态码可以提升API的可读性和用户体验:

kotlin 复制代码
// 成功响应
return Ok(data);                    // 200 - 请求成功
return Created(location, data);     // 201 - 资源已创建
return NoContent();                 // 204 - 操作成功,无返回内容

// 客户端错误
return BadRequest(errors);          // 400 - 请求格式错误
return Unauthorized();              // 401 - 未认证
return Forbid();                    // 403 - 无权限
return NotFound();                  // 404 - 资源不存在
return Conflict();                  // 409 - 资源冲突

// 服务器错误
return StatusCode(500, message);    // 500 - 服务器错误

AI写代码csharp
运行
1234567891011121314

七、配置与启动

Startup.csProgram.cs 中配置Web API服务:

ini 复制代码
// Program.cs (NET 6+)
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        // 自定义模型验证错误响应
        options.InvalidModelStateResponseFactory = context =>
        {
            var errors = context.ModelState.Values
                .SelectMany(v => v.Errors)
                .Select(e => e.ErrorMessage);
            return new BadRequestObjectResult(new { errors });
        };
    });

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); // API文档

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

AI写代码csharp
运行
123456789101112131415161718192021222324252627282930313233

总结

Web API开发的核心在于设计清晰的接口契约、处理好数据验证和错误情况,以及遵循RESTful原则。通过合理的架构设计和代码组织,可以构建出高质量、易维护的API服务。

关键要点:

  • 使用 [ApiController] 启用API增强功能
  • 实施完整的CRUD操作和错误处理
  • 合理使用HTTP状态码和验证机制
  • 采用依赖注入和异步编程模式
相关推荐
念念不忘 必有回响2 分钟前
viepress:vue组件展示和源码功能
前端·javascript·vue.js
C澒8 分钟前
多场景多角色前端架构方案:基于页面协议化与模块标准化的通用能力沉淀
前端·架构·系统架构·前端框架
崔庆才丨静觅9 分钟前
稳定好用的 ADSL 拨号代理,就这家了!
前端
江湖有缘11 分钟前
Docker部署music-tag-web音乐标签编辑器
前端·docker·编辑器
恋猫de小郭1 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端