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

如何在Apache Camel验证请求Header时返回自定义响应

问题描述

我是Apache Camel新手,正在基于Quarkus开发微服务,目前要实现输入字段的自动化验证,需对请求Header(x-correlator)进行验证,并返回400状态码和自定义响应格式。我已在DSL中配置了clientRequestValidation(true)和验证参数的代码:

param().name("x-correlator").type(RestParamType.header).required(true).endParam()

但当前返回的默认响应不符合预期,我希望得到自定义格式的响应。以下是我的RestRoute代码:

@ApplicationScoped
public class RestRoute extends RouteBuilder {
    @ConfigProperty(name = "client.url.userProfile")
    String urlUserProfile;

    @ConfigProperty(name = "client.utl.getActiveSessionByIp")
    String urlGetActivateSessionByIp;

    @ConfigProperty(name = "path.openapi")
    String pathOpenapi;

    @ConfigProperty(name = "descripcion.servicio")
    String descriptionService;

    private final IGetCurrentDateTime getCurrentDateTime;

    private ConfigureSsl configureSsl;

    private static final String SALIDA_BSS_EXCEPTION = "Salida Microservicio IdentifyOrigin ${body}";
    private static final String MSG_EXCEPTION = "Descripcion de la Exception: ${exception.message}";

    private static final String DATE_LOG = "[${bean:BeanDate.getCurrentDateTime()}] ";

    public RestRoute() {
        getCurrentDateTime = new GetCurrentDateTime();
        TimeZone.setDefault(TimeZone.getTimeZone("GMT-4"));
        configureSsl= new ConfigureSsl();
    }
    @Override
    public void configure() throws Exception {

        BeanDate beanDate= new BeanDate();
        getContext().getRegistry().bind("BeanDate", beanDate);

        restConfiguration().bindingMode(RestBindingMode.json).dataFormatProperty("json.in.disableFeatures","FAIL_ON_UNKNOWN_PROPERTIES")
                .clientRequestValidation(true)
                .apiContextPath(pathOpenapi)
                .apiProperty("api.title","IdentifyOrigin")
                .apiProperty("api.description",descriptionService)
                .apiProperty("api-version","1.0.0")
                .apiProperty("cors","true");
        rest("/api/")
                .produces("application/json")
                .consumes("application/json")
                .post("/identifyOrigin/v1/info")
                .type(Request.class)
                .param().name("x-correlator").type(RestParamType.header).required(true).endParam()
                .outType(ResponseSuccess.class)
                .param().name("Response").type(RestParamType.body).description("Parametros de Salidas")
                .required(true)
                .endParam().to("direct:pipeline");

                from("direct:pipeline")
                        .doTry()
                            .to("bean-validator:validateRequest")
                            .log("["+"${bean:BeanDate.getCurrentDateTime()}"+"] "+ "Datos de Entrada del MS: ${body}")
                            .process(new GetActivateSessionByIpReqProcessor())
                            .log("\n[${bean:BeanDate.getCurrentDateTime()}] "+"Entrada Microservicio GetActivateSessionByIp: ${exchangeProperty[getActivateSessionByIpRequest]}")
                            .to(configureSsl.setupSSLContext(getCamelContext(), urlGetActivateSessionByIp))
                            .choice()
                                .when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(200))
                                    .process(new GetActivateSessionByIpResProcessor())
                                    .log("["+"${bean:BeanDate.getCurrentDateTime()}"+"] "+ "Salida MS GetActivateSessionByIp: ${body}")
                                    .log("["+"${bean:BeanDate.getCurrentDateTime()}"+"] "+ "PhoneNumberByIp obtenido desde MS GetActivateSessionByIp: ${exchangeProperty[phoneNumberByIp]}")
                                    .process(new UserProfileReqProcessor())
                                    .to(configureSsl.setupSSLContext(getCamelContext(), urlUserProfile))
                                    .log("["+"${bean:BeanDate.getCurrentDateTime()}"+"] "+ "Datos de Salida del MS UserProfile: ${body}")
                            .otherwise()
                                .process(new ApiResponseFaultProcessor())
                            .end()
                            .process(new UserProfileReqProcessor())
                            .to(configureSsl.setupSSLContext(getCamelContext(), urlUserProfile))
                            .log("["+"${bean:BeanDate.getCurrentDateTime()}"+"] "+ "Datos de Salida del MS UserProfile: ${body}")
                            .choice()
                                .when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(200))
                                .process(new UserProfileResProcessor())
                                .log("["+"${bean:BeanDate.getCurrentDateTime()}"+"] "+ "UserId obtenido desde UserProfile: ${exchangeProperty[userId]}")
                                .process(new IdentifyOriginResProcessor())
                                .log(DATE_LOG+"Salida MS IdentifyOrigin: ${exchangeProperty[identifyOriginResponse]}")
                            .otherwise()
                                .process(new ApiResponseFaultProcessor())
                            .end()
                        .endDoTry()
                        .doCatch(BeanValidationException.class)
                            .process(new InvalidFormatExcepctionProcessor())
                            .log(DATE_LOG+MSG_EXCEPTION)
                            .log(DATE_LOG+SALIDA_BSS_EXCEPTION)
                        .doCatch(NotFoundDataException.class)
                            .process(new NotFoundDataExceptionProcessor())
                            .log(DATE_LOG+MSG_EXCEPTION)
                            .log(DATE_LOG+SALIDA_BSS_EXCEPTION)
                        .doCatch(HttpHostConnectException.class)
                            .process(new HttpHostConnectExceptionProcessor())
                            .log(DATE_LOG+MSG_EXCEPTION)
                            .log(DATE_LOG+SALIDA_BSS_EXCEPTION)
                        .doCatch(Exception.class)
                            .process(new IdentifyOriginExceptionProcessor())
                            .log(DATE_LOG+MSG_EXCEPTION)
                            .log(DATE_LOG+SALIDA_BSS_EXCEPTION);
    }
}

请问如何实现自定义响应?

解决方案

核心问题是clientRequestValidation(true)触发的异常是RestValidationException,而非你当前捕获的BeanValidationException,导致默认响应未被自定义逻辑处理。按以下步骤修改:

1. 添加RestValidationException捕获逻辑

在路由的doCatch块中新增对该异常的捕获,指定自定义处理器:

.doCatch(RestValidationException.class)
    .process(new RestValidationExceptionProcessor())
    .log(DATE_LOG+MSG_EXCEPTION)
    .log(DATE_LOG+SALIDA_BSS_EXCEPTION)

注意将这个doCatch放在Exception类型捕获的前面,因为Camel会按顺序匹配异常,更具体的异常需要优先处理。

2. 实现自定义异常处理器

创建RestValidationExceptionProcessor类,将异常信息转换为你需要的响应格式,并设置400状态码:

public class RestValidationExceptionProcessor implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        RestValidationException exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, RestValidationException.class);
        
        // 构建自定义错误响应实体
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setCode("400");
        errorResponse.setMessage("请求参数验证失败");
        errorResponse.setDetails(exception.getErrors().stream()
                .map(RestValidationError::getMessage)
                .collect(Collectors.toList()));
        
        // 设置响应体和状态码
        exchange.getIn().setBody(errorResponse);
        exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
    }
}

(注:ErrorResponse是你自定义的响应实体类,需根据业务需求调整字段结构)

3. 可选:全局异常处理替代路由内捕获

如果需要统一处理所有RestValidationException,可以使用Camel的全局异常处理机制,替代路由内的doCatch:

@Override
public void configure() throws Exception {
    // 全局异常处理
    onException(RestValidationException.class)
        .handled(true)
        .process(new RestValidationExceptionProcessor())
        .log(DATE_LOG+MSG_EXCEPTION);
    
    // 原有路由配置...
}

补充说明

  • clientRequestValidation负责验证Rest DSL中定义的参数(如header、path参数),而bean-validator负责验证请求体的Bean校验注解,两者触发的异常类型不同,需分别处理。
  • 确保ErrorResponse类配置了正确的JSON序列化注解(如Jackson的@JsonProperty),保证响应格式符合预期。

内容的提问来源于stack exchange,提问作者Cesar Justo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:20:33