Camel Rest DSL搭配Jetty组件时CORS响应头填充异常问题咨询
解决Camel Rest DSL + Jetty下动态匹配CORS Origin的问题
Camel Rest DSL的默认CORS处理逻辑会直接将配置的Access-Control-Allow-Origin值原样返回,不会根据请求的Origin头动态匹配并返回对应值。要实现匹配允许列表返回请求Origin、不匹配则返回错误的需求,需要绕过Camel的默认CORS配置,通过自定义逻辑处理,以下是两种可行方案:
方案一:自定义Processor拦截处理CORS逻辑
关闭Camel默认CORS配置
删掉或注释掉原配置中所有camel.rest.cors-headers相关项,避免Camel覆盖自定义响应头。编写动态CORS处理Processor
实现Camel的Processor接口,在其中完成Origin校验、响应头设置和OPTIONS预检请求处理:import org.apache.camel.Exchange; import org.apache.camel.Processor; import javax.servlet.http.HttpServletRequest; import java.util.Set; import java.util.regex.Pattern; public class DynamicCorsProcessor implements Processor { // 允许的Origin规则集合 private final Set<String> allowedOriginPatterns = Set.of( "*.example.com", "*.example1.com", "*.example2.com" ); @Override public void process(Exchange exchange) throws Exception { HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class); String requestOrigin = request.getHeader("Origin"); // 跳过非跨域请求(无Origin头) if (requestOrigin == null) { return; } // 校验请求Origin是否匹配允许规则 boolean isAllowed = allowedOriginPatterns.stream() .anyMatch(pattern -> { // 将通配符转为正则表达式 String regex = pattern.replace("*", ".*").replace(".", "\\."); return Pattern.compile(regex).matcher(requestOrigin).matches(); }); if (isAllowed) { // 设置CORS响应头 exchange.getOut().setHeader("Access-Control-Allow-Origin", requestOrigin); exchange.getOut().setHeader("Access-Control-Allow-Credentials", "true"); exchange.getOut().setHeader("Access-Control-Max-Age", "3600"); exchange.getOut().setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); exchange.getOut().setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent, Authorization, x-omit"); // 处理OPTIONS预检请求,直接返回200 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200); exchange.getOut().setBody(null); } } else { // 不允许的Origin,返回403错误 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 403); exchange.getOut().setBody("Invalid Origin"); } } }绑定Processor到路由
可以将Processor绑定到单个Rest路由,或者通过全局拦截器作用于所有Jetty端点:// 单个路由绑定 restConfiguration().component("jetty").port(8080); rest("/api") .get("/resource") .route() .process(new DynamicCorsProcessor()) .to("direct:handleResource"); // 全局拦截所有Jetty请求 interceptFrom("jetty:*") .process(new DynamicCorsProcessor());
方案二:集成Jetty原生CorsFilter
Jetty自带的CorsFilter支持动态匹配请求Origin,且优先级高于Camel的默认处理,步骤如下:
关闭Camel默认CORS配置
同方案一,移除所有camel.rest.cors-headers配置。配置Jetty CorsFilter并集成Camel
手动创建Jetty服务器和上下文,添加CorsFilter后绑定Camel的Servlet:import org.apache.camel.component.jetty.CamelHttpTransportServlet; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlets.CorsFilter; import javax.servlet.DispatcherType; import java.util.EnumSet; public class JettyCorsSetup { public static void main(String[] args) throws Exception { // 初始化Jetty服务器 Server jettyServer = new Server(8080); // 创建Servlet上下文 ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); // 配置Jetty CorsFilter CorsFilter corsFilter = new CorsFilter(); corsFilter.setAllowedOrigins("*.example.com,*.example1.com,*.example2.com"); corsFilter.setAllowedMethods("GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); corsFilter.setAllowedHeaders("Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent, Authorization, x-omit"); corsFilter.setAllowCredentials(true); corsFilter.setMaxAge(3600); corsFilter.setAllowOriginRegex(true); // 启用正则匹配通配符规则 context.addFilter(corsFilter, "/*", EnumSet.allOf(DispatcherType.class)); // 绑定Camel Servlet到上下文 ServletHolder camelServletHolder = new ServletHolder(new CamelHttpTransportServlet()); context.addServlet(camelServletHolder, "/api/*"); // 启动Jetty jettyServer.setHandler(context); jettyServer.start(); // 初始化Camel上下文和路由 org.apache.camel.CamelContext camelContext = new org.apache.camel.impl.DefaultCamelContext(); camelContext.addRoutes(new org.apache.camel.builder.RouteBuilder() { @Override public void configure() throws Exception { rest("/api") .get("/resource") .to("direct:handleResource"); from("direct:handleResource") .setBody(constant("Success")); } }); camelContext.start(); } }
注意事项
- 必须确保Camel的默认CORS配置已完全关闭,否则会覆盖自定义设置的响应头。
- 通配符匹配时,
*.example.com会匹配sub.example.com但不会匹配example.com,如果需要包含顶级域名,需单独添加example.com到允许列表。 - 对于OPTIONS预检请求,需确保返回正确的响应头和200状态码,否则浏览器会阻止后续请求。
内容的提问来源于stack exchange,提问作者Navinya Shende
相关产品推荐
相关产品推荐

