11.1 RESTful API 设计原则
核心原则:资源为中心(如/api/users)、HTTP 方法语义(GET 查询 / POST 创建 / PUT 更新 / DELETE 删除)、无状态、返回标准状态码。
规范示例:
|
需求 |
HTTP 方法 |
接口路径 |
状态码 |
|
查询所有用户 |
GET |
/api/users |
200 OK |
|
查询单个用户 |
GET |
/api/users/{id} |
200 OK/404 Not Found |
|
创建用户 |
POST |
/api/users |
201 Created |
|
全量更新用户 |
PUT |
/api/users/{id} |
204 No Content |
|
部分更新用户 |
PATCH |
/api/users/{id} |
204 No Content |
|
删除用户 |
DELETE |
/api/users/{id} |
204 No Content |
11.2 控制器设计与路由配置
控制器核心规则:继承ControllerBase(API 控制器无需视图)、用[ApiController]标记(自动启用模型验证、路由推断)。
路由配置方式:
- 特性路由(推荐 API 使用):[Route(“api/[controller]/[action]”)] 或 固定路由 [Route(“api/v1/users”)]。
- 约定路由(全局配置,适合简单场景):app.MapControllerRoute(name: “default”, pattern: “api/{controller}/{action}/{id?}”);。
实战案例:用户管理 API 控制器:
[ApiController]
[Route("api/v1/[controller]")] // 路由:/api/v1/users
public class UsersController : ControllerBase
{
private readonly AppDbContext _dbContext;
public UsersController(AppDbContext dbContext)
{
_dbContext = dbContext;
}
// 1. 查询所有用户(支持分页)
[HttpGet]
public async Task<ActionResult<List<UserDto>>> GetUsers(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 10)
{
var total = await _dbContext.Users.CountAsync();
var users = await _dbContext.Users
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(u => new UserDto // 用DTO避免暴露实体完整属性
{
Id = u.Id,
Name = u.Name,
Email = u.Email,
Age = u.Age
})
.ToListAsync();
// 返回分页结果
return Ok(new PagedResult<UserDto>
{
Total = total,
Page = page,
PageSize = pageSize,
Data = users
});
}
// 2. 查询单个用户(路由参数:id)
[HttpGet("{id}")]
public async Task<ActionResult<UserDto>> GetUserById(int id)
{
var user = await _dbContext.Users.FindAsync(id);
if (user == null)
{
return NotFound(new { Message = "用户不存在" }); // 404状态码
}
var userDto = new UserDto
{
Id = user.Id,
Name = user.Name,
Email = user.Email,
Age = user.Age
};
return Ok(userDto);
}
// 3. 创建用户(请求体:FromBody)
[HttpPost]
public async Task<ActionResult<UserDto>> CreateUser([FromBody] CreateUserRequest request)
{
// 模型验证(由[ApiController]自动触发,验证失败返回400)
var user = new User
{
Name = request.Name,
Email = request.Email,
Age = request.Age,
CreateTime = DateTime.Now
};
_dbContext.Users.Add(user);
await _dbContext.SaveChangesAsync();
// 返回201 Created,包含新用户ID
var userDto = new UserDto
{
Id = user.Id,
Name = user.Name,
Email = user.Email,
Age = user.Age
};
return CreatedAtAction(nameof(GetUserById), new { id = user.Id }, userDto);
}
// 4. 删除用户
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteUser(int id)
{
var user = await _dbContext.Users.FindAsync(id);
if (user == null)
{
return NotFound();
}
_dbContext.Users.Remove(user);
await _dbContext.SaveChangesAsync();
return NoContent(); // 204 No Content(无返回体)
}
}
// 辅助类:DTO与请求模型
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
public class CreateUserRequest
{
[Required(ErrorMessage = "用户名不能为空")]
[MaxLength(50, ErrorMessage = "用户名最长50个字符")]
public string Name { get; set; }
[Required(ErrorMessage = "邮箱不能为空")]
[EmailAddress(ErrorMessage = "邮箱格式错误")]
public string Email { get; set; }
[Range(18, 100, ErrorMessage = "年龄必须在18-100之间")]
public int Age { get; set; }
}
public class PagedResult<T>
{
public int Total { get; set; } // 总条数
public int Page { get; set; } // 当前页
public int PageSize { get; set; } // 每页条数
public List<T> Data { get; set; } // 数据列表
}
11.3 模型绑定与数据验证
模型绑定来源:[FromQuery](URL 查询参数)、[FromRoute](路由参数)、[FromBody](请求体,如 JSON)、[FromForm](表单数据)、[FromHeader](请求头)。
数据验证:通过DataAnnotations特性(如[Required]、[EmailAddress])定义规则,[ApiController]自动触发验证,失败返回400 Bad Request。
自定义验证案例:
// 自定义验证特性:邮箱不能包含特定域名
public class NoInvalidDomainAttribute : ValidationAttribute
{
private readonly string _invalidDomain;
public NoInvalidDomainAttribute(string invalidDomain)
{
_invalidDomain = invalidDomain;
ErrorMessage = $"邮箱不能包含域名:{invalidDomain}";
}
public override bool IsValid(object value)
{
var email = value as string;
if (string.IsNullOrEmpty(email))
{
return true; // 非空验证由[Required]处理
}
return !email.EndsWith(_invalidDomain, StringComparison.OrdinalIgnoreCase);
}
}
// 在请求模型中使用
public class CreateUserRequest
{
// ... 其他属性
[Required(ErrorMessage = "邮箱不能为空")]
[EmailAddress(ErrorMessage = "邮箱格式错误")]
[NoInvalidDomain("@test.com")] // 自定义验证:禁止test.com邮箱
public string Email { get; set; }
}
11.4 内容协商与格式化器
内容协商:API 根据请求头Accept自动返回对应格式(如application/json返回 JSON,application/xml返回 XML)。
配置 XML 格式化器(默认仅支持 JSON):
// Program.cs中添加XML格式化器
builder.Services.AddControllers()
.AddXmlSerializerFormatters(); // 启用XML序列化
// 测试:请求头添加Accept: application/xml,返回XML格式响应
11.5 API 版本控制策略
常用版本控制方式:URL 路径(如/api/v1/users)、查询参数(如/api/users?api-version=1)、请求头(如api-version: 1)。
实战案例:URL 路径版本控制:
- 安装 NuGet 包:Microsoft.AspNetCore.Mvc.Versioning。
- 配置版本控制:
// Program.cs
builder.Services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true; // 未指定版本时使用默认版本
options.DefaultApiVersion = new ApiVersion(1, 0); // 默认版本1.0
options.ReportApiVersions = true; // 响应头返回支持的版本
});
- 定义多版本控制器:
// V1版本控制器
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
public class UsersController : ControllerBase
{
[HttpGet]
public IActionResult GetUsersV1()
{
return Ok(new { Version = "1.0", Data = "V1版本用户列表" });
}
}
// V2版本控制器(新增字段)
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("2.0")]
public class UsersController : ControllerBase
{
[HttpGet]
public IActionResult GetUsersV2()
{
return Ok(new { Version = "2.0", Data = "V2版本用户列表(含创建时间)" });
}
}
访问/api/v1/users返回 V1 结果
/api/v2/users返回 V2 结果。