如何让多个WireMock实例共享同一请求日志(Journal)
解决WireMock多实例共享请求日志的方案
针对你在带负载均衡的可扩展环境中使用spring-cloud-contract-wiremock时遇到的请求日志验证问题,以下是几种可行的解决方案:
1. 自定义请求日志存储实现
WireMock的请求日志(Request Journal)默认使用内存存储InMemoryRequestJournal,但它提供了可扩展的接口RequestJournal,你可以自行实现该接口,将请求数据持久化到共享存储(数据库或共享文件系统)。
实现步骤:
- 实现
RequestJournal接口,核心是重写record(记录请求)、getRequests(查询请求)和reset(清空日志)方法,将请求序列化为JSON后写入共享存储,查询时再反序列化返回。 - 在Spring配置中替换默认的日志实现,指定自定义的
RequestJournal实例。
示例代码(基于数据库存储):
public class DbBackedRequestJournal implements RequestJournal { private final JdbcTemplate jdbcTemplate; public DbBackedRequestJournal(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; // 初始化请求日志表(首次运行时执行) jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS wiremock_requests (" + "id BIGINT AUTO_INCREMENT PRIMARY KEY," + "request_json TEXT NOT NULL," + "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"); } @Override public void record(Request request) { String requestJson = Json.write(request); jdbcTemplate.update("INSERT INTO wiremock_requests (request_json) VALUES (?)", requestJson); } @Override public List<LoggedRequest> getRequests() { return jdbcTemplate.query("SELECT request_json FROM wiremock_requests ORDER BY created_at DESC", (rs, rowNum) -> Json.read(rs.getString("request_json"), LoggedRequest.class)); } @Override public void reset() { jdbcTemplate.update("TRUNCATE TABLE wiremock_requests"); } // 实现接口其他默认方法 @Override public List<LoggedRequest> find(RequestPattern requestPattern) { return getRequests().stream() .filter(request -> requestPattern.match(request).isExactMatch()) .collect(Collectors.toList()); } }
Spring配置整合:
@Bean public WireMockServer wireMockServer(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); return new WireMockServer(wireMockConfig() .port(8080) .requestJournal(new DbBackedRequestJournal(jdbcTemplate))); }
2. 统一请求收集代理
在负载均衡器与WireMock实例之间添加一层轻量代理,所有请求先经过代理,由代理负责将请求日志写入共享存储,再转发请求到WireMock实例。验证时直接从代理的共享存储中查询日志即可。
这种方式无需修改WireMock代码,适合快速落地:
- 可以用Nginx配置日志模块,将请求日志写入共享文件系统;
- 也可以自定义一个Spring Boot代理服务,在转发请求的同时记录请求到数据库或Redis。
3. 分布式查询验证逻辑
如果不想修改存储实现,可以调整测试验证逻辑,通过服务发现获取所有WireMock实例的地址,逐个查询实例的请求日志接口/__admin/requests,汇总结果后验证请求是否存在。
示例代码:
// 从服务发现获取所有WireMock实例地址 List<String> wireMockInstances = serviceDiscovery.getInstances("wiremock-service") .stream() .map(instance -> instance.getUri().toString()) .collect(Collectors.toList()); String testRequestId = "unique-test-123"; // 测试请求中携带的唯一标识(比如X-Test-Id头) boolean requestProcessed = false; RestTemplate restTemplate = new RestTemplate(); for (String instanceUrl : wireMockInstances) { String requestUrl = instanceUrl + "/__admin/requests?headers.X-Test-Id=" + testRequestId; ResponseEntity<List<Map>> response = restTemplate.getForEntity(requestUrl, List.class); if (!response.getBody().isEmpty()) { requestProcessed = true; break; } } // 断言请求已被处理 assertTrue(requestProcessed);
4. 使用WireMock扩展插件
部分第三方扩展插件支持将请求日志存储到Redis等分布式存储中,你可以根据spring-cloud-contract-wiremock的版本选择兼容的插件,直接集成使用,无需自行实现存储逻辑。
内容的提问来源于stack exchange,提问作者Jacinto Barbeira
相关产品推荐
相关产品推荐

