You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:07:45