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 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子2 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年2 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子2 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina2 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路3 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说4 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409194 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding4 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜4 小时前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui