如何将Quarkus中SmallRye Health响应类型改为application/problem+json?
解决方案:将SmallRye Health响应转换为RFC7807格式
要实现将Quarkus中SmallRye Health的默认application/json响应替换为application/problem+json(及可选的application/problem+xml),核心思路是拦截健康端点的响应,转换为RFC7807定义的Problem结构并修改Content-Type。以下是具体实现步骤:
1. 定义RFC7807 Problem实体类
先创建符合RFC7807规范的实体类,用于封装响应内容:
import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.NON_NULL) public class Problem { private String type; private String title; private int status; private String detail; private String instance; public Problem(String type, String title, int status, String detail, String instance) { this.type = type; this.title = title; this.status = status; this.detail = detail; this.instance = instance; } // 自动生成getter和setter(可使用Lombok简化) public String getType() { return type; } public void setType(String type) { this.type = type; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } public String getInstance() { return instance; } public void setInstance(String instance) { this.instance = instance; } }
2. 实现响应拦截过滤器
通过ContainerResponseFilter拦截健康端点的响应,完成格式转换和Content-Type修改:
import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerResponseContext; import jakarta.ws.rs.container.ContainerResponseFilter; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; import org.eclipse.microprofile.health.HealthCheckResponse; import java.io.IOException; import java.util.List; @Provider public class HealthProblemResponseFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { // 匹配重映射后的健康端点(含子端点如/status/live、/status/ready) String path = requestContext.getUriInfo().getPath(); if (!"/status".equals(path) && !path.startsWith("/status/")) { return; } Object entity = responseContext.getEntity(); if (entity == null) return; int statusCode = responseContext.getStatus(); boolean isHealthy = statusCode == Response.Status.OK.getStatusCode(); String title = isHealthy ? "All Checks Passed" : "Service Unhealthy"; String detail; // 处理单个健康检查响应或聚合响应 if (entity instanceof HealthCheckResponse) { HealthCheckResponse hcResp = (HealthCheckResponse) entity; detail = String.format("%s: %s", hcResp.getName(), hcResp.getStatus()); } else if (entity instanceof List<?>) { StringBuilder detailBuilder = new StringBuilder(); for (Object item : (List<?>) entity) { if (item instanceof HealthCheckResponse) { HealthCheckResponse hc = (HealthCheckResponse) item; detailBuilder.append(hc.getName()).append(": ").append(hc.getStatus()).append("; "); } } detail = detailBuilder.toString().trim(); } else { detail = "Health check response"; } // 构建RFC7807 Problem对象 Problem problem = new Problem( isHealthy ? "about:blank" : "https://your-domain.com/problems/service-unhealthy", title, statusCode, detail, requestContext.getUriInfo().getRequestUri().toString() ); // 更新响应体和Content-Type为application/problem+json responseContext.setEntity(problem); responseContext.getHeaders().putSingle("Content-Type", MediaType.APPLICATION_JSON.withSubtype("problem+json")); // 可选:根据Accept头支持application/problem+xml List<MediaType> acceptTypes = requestContext.getAcceptableMediaTypes(); for (MediaType mt : acceptTypes) { if (MediaType.APPLICATION_XML.withSubtype("problem+xml").isCompatible(mt)) { responseContext.getHeaders().putSingle("Content-Type", MediaType.APPLICATION_XML.withSubtype("problem+xml")); break; } } } }
3. 配置与依赖补充
端点重映射确认
确保你已经在application.properties中完成端点重映射:
quarkus.http.paths./status=/q/health
XML格式支持(可选)
如果需要application/problem+xml响应,添加Jackson XML依赖到pom.xml:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson-xml</artifactId> </dependency>
4. 测试效果
启动应用后请求/status端点,健康状态下的响应示例:
{ "type": "about:blank", "title": "All Checks Passed", "status": 200, "detail": "Liveness check: UP; Datasource check: UP;", "instance": "http://localhost:8080/status" }
响应头的Content-Type会显示为application/problem+json(或根据Accept头切换为application/problem+xml)。
内容的提问来源于stack exchange,提问作者vscut
相关产品推荐
相关产品推荐

