
1) 【一句话结论】:设计一个支持分页、排序、筛选的RESTful接口,通过令牌桶限流控制请求速率,并采用结构化日志记录请求时间、响应时间及错误信息,确保接口性能与可观测性。
2) 【原理/概念讲解】:
/students/courses),参数通过查询字符串传递(分页page/size、排序sort/direction、筛选filter)。page(当前页)、size(每页数量)控制数据量,避免一次性返回过多数据。sort(字段名)、direction(asc/desc)指定排序规则。filter(字段=值)过滤数据,支持多条件(如status=active&grade=high)。request_time(请求时间)、response_time(响应时间)、params(请求参数)、response(响应数据)、error(错误信息),便于日志分析(如ELK)。3) 【对比与适用场景】:
限流算法对比(令牌桶 vs 漏桶):
| 算法 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 令牌桶 | 维护固定容量桶,每秒生成固定令牌,请求消耗令牌 | 允许突发流量(桶满后请求等待),速率恒定 | 突发流量(如促销活动) | 需设置桶容量与令牌生成速率 |
| 漏桶 | 维护固定容量桶,以固定速率向桶中添加令牌,请求消耗令牌 | 速率平滑,限制最大速率 | 严格速率限制(如API调用限制) | 需设置桶容量与漏速率 |
4) 【示例】:
GET /api/students/coursesGET /api/students/courses?page=1&size=10&sort=courseName,asc&filter=status=active&grade=high
@GetMapping("/courses")
public ResponseEntity<PagedResult<Course>> getCourses(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "courseName") String sort,
@RequestParam(defaultValue = "asc") String direction,
@RequestParam Map<String, String> filter) {
// 分页、排序、筛选逻辑
PagedResult<Course> result = courseService.getCourses(page, size, sort, direction, filter);
return ResponseEntity.ok(result);
}
RateLimiter rateLimiter = RateLimiter.create(10); // 10请求/秒
rateLimiter.acquire(); // 获取令牌,超时则拒绝
log.info("request_time={}, response_time={}, params={}, response={}, error={}",
startTime, endTime, params, result, error);
5) 【面试口播版答案】:
“面试官您好,设计这个RESTful接口的核心是支持分页、排序、筛选,同时通过限流和日志记录保障性能与可观测性。首先,接口设计上,路径用/students/courses,通过查询参数实现分页(page/size)、排序(sort/direction)、筛选(filter),比如page=1&size=10&sort=courseName,asc&filter=status=active。然后,限流方面,采用令牌桶算法,用Guava的RateLimiter,配置为每秒10请求,确保恶意请求不会压垮服务器。日志记录用结构化日志,记录请求时间、响应时间、参数、响应数据,方便后续分析。具体实现时,在Controller层调用限流中间件,然后调用服务层处理分页、排序、筛选,最后记录日志。这样既保证了接口的灵活性,又通过限流和日志提升了系统的稳定性和可维护性。”
6) 【追问清单】:
page=1,size=10,避免空值导致错误。@Query或MyBatis的#{}),避免注入风险。7) 【常见坑/雷区】: