ES客户端8版本与ES服务端7版本的兼容问题

news/2025/10/12 23:33:46/文章来源:https://www.cnblogs.com/zlw-miaomiao/p/19137504

🎬 第一阶段:发现问题(认识症状)

🔴 看到的错误日志:

2025-09-30 14:23:45.123 ERROR - ES全量同步任务执行失败
co.elastic.clients.transport.TransportException: 
Missing [X-Elastic-Product] header. 
Please check that you are connecting to an Elasticsearch instance, 
error trace ElasticsearchException[Missing [X-Elastic-Product] header]

💭 我的第一反应:

思考1: "Missing header" - 缺少HTTP头部↓
思考2: 这个错误很具体,是ES客户端在检查某个头部↓
思考3: 先去Google搜一下这个错误

🔎 第二阶段:信息收集(10分钟)

搜索关键词:elasticsearch Missing X-Elastic-Product header

找到几个关键信息:

Stack Overflow:
"This error occurs when using Elasticsearch 8.x client with Elasticsearch 7.x server"GitHub Issue:
"ES 8.x client requires X-Elastic-Product header in responsebut ES 7.x server doesn't send it"官方文档:
"Starting from 8.0, the client validates the server by checking the X-Elastic-Product header"

💡 初步结论:

问题根源:
├─ ES 8.x 客户端有新的安全检查
├─ 要求服务器响应必须包含 X-Elastic-Product 头部
└─ ES 7.x 服务器不返回这个头部解决方向:
1. 升级服务器到8.x(成本高)
2. 降级客户端到7.x(依赖地狱)
3. 让客户端跳过检查(可能不安全)
4. 在响应中添加这个头部(?如何做到)

🧪 第三阶段:第一次尝试(方向错误)

❌ 尝试1:在请求中添加头部(15分钟)

我的想法:

"既然缺少头部,那我在请求中加上不就行了?"

修改代码:

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("X-Elastic-Product", "Elasticsearch");

结果:

还是报同样的错误!为什么?
仔细看错误信息:"Missing [X-Elastic-Product] header"
客户端是在检查响应,不是请求!❌ 方向错了!

💭 反思:

错误分析:
我理解错了问题
- 客户端发送请求 → 服务器
- 服务器返回响应 → 客户端
- 客户端检查响应头部 ← 这里出错了!所以:
✅ 需要修改的是:服务器的响应
❌ 不是:客户端的请求

🔄 第四阶段:调整思路(关键转折)

💡 新思路:

问题:客户端检查响应头↓
难点:我改不了服务器(ES 7.x本身)↓
想法:能不能在响应到达客户端之前,先"拦截"它,然后添加头部?↓
关键词:HTTP 拦截器(Interceptor)

🔍 搜索:apache httpclient response interceptor

找到了:

HttpResponseInterceptor
- 可以拦截HTTP响应
- 在响应到达客户端前处理
- 可以修改响应头部✅ 这就是我要找的!

🛠️ 第五阶段:第二次尝试(方向正确但实现有问题)

✅ 尝试2:使用响应拦截器(30分钟)

第一版代码:

HttpResponseInterceptor interceptor = new HttpResponseInterceptor() {@Overridepublic void process(HttpResponse response, HttpContext context) {response.addHeader("X-Elastic-Product", "Elasticsearch");}
};// 但是在哪里注册这个拦截器???

🤔 问题:拦截器应该注册在哪里?

查看ES客户端的层级结构:

调用顺序(从上到下):ElasticsearchClient(高层API)↓
RestClientTransport(传输层)↓
RestClient(HTTP客户端)← 在这里!↓
Apache HttpClient(底层HTTP)← 拦截器在这里工作

查找RestClient的API文档:

RestClient.builder(HttpHost...).setHttpClientConfigCallback(callback -> {// 在这里可以配置Apache HttpClient// 包括添加拦截器!})

💡 找到了注册位置!

📝 第六阶段:编写完整代码(20分钟)

完整实现:

@Bean
@Primary
public RestClient elasticsearchRestClient() {// 1. 创建响应拦截器HttpResponseInterceptor responseInterceptor = new HttpResponseInterceptor() {@Overridepublic void process(HttpResponse response, HttpContext context) {if (!response.containsHeader("X-Elastic-Product")) {response.addHeader("X-Elastic-Product", "Elasticsearch");log.debug("✅ 已添加 X-Elastic-Product 头部");}}};// 2. 创建RestClient,注册拦截器RestClientBuilder builder = RestClient.builder(new HttpHost(host, port, scheme)).setHttpClientConfigCallback(httpClientBuilder -> {// 3. 在这里添加拦截器到Apache HttpClienthttpClientBuilder.addInterceptorLast(responseInterceptor);return httpClientBuilder;});return builder.build();
}

🐛 第七阶段:编译和运行(遇到新问题)

❌ 问题3:Bean冲突(10分钟)

编译通过,但运行报错:

BeanCreationException: 
Error creating bean with name 'elasticsearchClient': 
Ambiguous factory method matches found

分析:

原因:
我的配置类继承了 ElasticsearchConfiguration↓
ElasticsearchConfiguration 已经提供了 elasticsearchClient bean↓
我又自己定义了一个 elasticsearchClient bean↓
Spring 不知道用哪个!

解决:

// 移除继承
// public class ElasticsearchClientConfig extends ElasticsearchConfiguration {// 改为
public class ElasticsearchClientConfig {// 手动定义所有需要的Bean
}

🔄 第八阶段:补全所有Bean(30分钟)

问题:移除继承后,缺少其他Bean

NoSuchBeanDefinitionException: 
No qualifying bean of type 
'org.springframework.data.elasticsearch.core.ElasticsearchOperations'

💭 分析Bean依赖关系:

需要的Bean链条:ElasticsearchOperations(Spring Data的核心接口)↓ 需要
ElasticsearchTemplate(实现类)↓ 需要
ElasticsearchClient(ES客户端)↓ 需要
RestClient(HTTP客户端)← 我已经有了还需要:
ElasticsearchConverter(数据转换器)

补全所有Bean:

@Bean
@Primary
public RestClient elasticsearchRestClient() {// 已有
}@Bean
@Primary
public ElasticsearchClient elasticsearchClient(RestClient restClient) {RestClientTransport transport = new RestClientTransport(restClient,new JacksonJsonpMapper());return new ElasticsearchClient(transport);
}@Bean
@Primary
public ElasticsearchConverter elasticsearchConverter() {return new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
}@Bean
@Primary
public ElasticsearchOperations elasticsearchOperations(ElasticsearchClient elasticsearchClient,ElasticsearchConverter elasticsearchConverter) {return new ElasticsearchTemplate(elasticsearchClient,elasticsearchConverter);
}

🚀 第九阶段:首次成功运行(但还有其他问题)

✅ 响应拦截器工作了!

日志显示:

✅ 响应拦截器已添加头部: X-Elastic-Product=Elasticsearch
✅ Elasticsearch客户端验证通过

❌ 但出现了新错误:

java.lang.reflect.InaccessibleObjectException: 
Unable to make field private final java.math.BigInteger 
java.math.BigDecimal.intVal accessible: 
module java.base does not "opens java.math" to unnamed module

🔧 第十阶段:解决BigDecimal问题(20分钟)

💭 分析新错误:

错误原因:
Java 17的模块系统限制了反射访问↓
Spring Data Elasticsearch在序列化时
需要反射访问BigDecimal的内部字段↓
但Java 17不允许这样做

尝试的解决方案:

方案A:添加JVM参数(不推荐)

--add-opens java.base/java.math=ALL-UNNAMED

✅ 可以工作,但是治标不治本

方案B:改用Double(推荐)

// 修改实体类
@Field(type = FieldType.Double)
private Double standardPrice;  // 从 BigDecimal 改为 Double// 修改同步逻辑
esProduct.setStandardPrice(product.getStandardPrice() != null ? product.getStandardPrice().doubleValue() : null
);

✅ 彻底解决,不需要JVM参数

我选择了方案B

🧹 第十一阶段:清理旧代码(10分钟)

删除不需要的文件:

❌ ElasticsearchRequestOptionsConfig.java- 使用旧API(RequestOptions)- ES 8.x不再需要- 功能已被响应拦截器替代

更新配置文件:

# 禁用兼容性配置(因为已经在主配置中处理)
commerce:elasticsearch:compatibility:enabled: false

✅ 第十二阶段:全面测试和验证(30分钟)

测试清单:

✅ 1. 应用启动测试- ElasticsearchClientConfig 正确初始化- 所有Bean正确创建- 无错误日志✅ 2. ES连接测试- 响应拦截器正常工作- X-Elastic-Product头部正确添加- 客户端验证通过✅ 3. 数据同步测试- XXL-JOB任务触发- 商品数据正确同步- 价格字段正确转换(Double)- 返回码:200✅ 4. 搜索功能测试- 索引创建成功- 数据可以搜索- 性能正常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/935795.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI 改变数据库产品实践探索

AI 改变数据库产品实践探索OceanBase 结合 AI 技术,通过 Agent 和任务调度简化数据库操作,支持多数据库管理与易用性提升。01 obloader agent 导数工具使用中的难题 在实际使用导数工具进行数据导入的过程中,用户普…

使用Sender和io_uring改造Webserver

前言 我以前有写过一个练手玩具,参考 tinywebserver 当然那时候我稍微改了下,改成了主从 Reactor 和 epoll 不过那时候感觉最后实现的有线程问题,查了半天没查出来红温了,索性加了一把大锁 最近读了下 Sender 模型…

乐理 -04 打拍子

.. 四N拍子 打拍子.....附点小切分 强的在中间大附点&大切分八N拍子 打拍子 3个

如何在Renpy尝试中调整人物和背景图像大小

在初步绘制好立绘或者是背景后,如果直接存入images文件中进行图像调用,往往会出现图像过于大或者是过于小,导致当前场景观感不佳等问题。 解决方案主要有两种: (1)重新选择较大或者是较小的画布,重新绘制立绘,…

开源软件站

1. OSCHINA - 中文开源技术交流社区 https://www.oschina.net/2. 开源软件 - Gitee.com3. Trending repositories on GitHub today GitHub4. Explore projects GitLab5. GitCode - 全球开发者的开源社区,开源代码托…

如何安装claude code以及ccr code

如何安装claude code以及ccr code 1. 安装 node 1.1 node的常规安装(适用于linux18.04,linux20.04等新版本) 参考官网安装顺序:https://nodejs.org/en/download 1.2 常规安装失败,其他情况下node的安装(适用于li…

代码托管平台

1. 开源软件 - Gitee.com2. Trending repositories on GitHub today GitHub3. Explore projects GitLab4. GitCode - 全球开发者的开源社区,开源代码托管平台5. 腾讯Coding 2025年10月12日停止注册,推荐CNB - Cloud…

209. 长度最小的子数组 滑动窗口+暴力

209. 长度最小的子数组 滑动窗口 思路 初始化滑动窗口的起始位置 left = 0、终止位置 right = 0。 外循环先确定滑动窗口的终止位置(增大滑动窗口),找到符合条件的子序列, 根据当前子序列元素和大小的情况,在内循…

CISA事件响应实战经验:漏洞修复与应急响应关键教训

美国网络安全和基础设施安全局分享了一起联邦机构遭攻击事件的技术分析,详细介绍了攻击者利用GeoServer漏洞的入侵过程、横向移动技术,并总结了漏洞修复、应急响应计划和日志监控三个关键教训。执行摘要 CISA在美国联…

机器人视觉系统在复杂环境中的自主决策与学习

本文介绍了某中心研发的Robin机器人视觉系统,该系统通过机器学习技术实现复杂场景下的物体识别与抓取决策,具备持续学习能力,能够从错误中自动学习并提升分拣准确率,展示了机器人感知系统在生产环境中的实际应用。…

2025开关按钮厂家最新权威推荐榜:品质卓越与创新设计的行业

2025开关按钮厂家最新权威推荐榜:品质卓越与创新设计的行业随着工业自动化和智能化的发展,开关按钮作为关键的控制元件,在各个行业中扮演着越来越重要的角色。为了帮助筛选开关按钮品牌,特此发布权威推荐榜单,为采…

正睿25noip十连测day5

题面:今天有点 fvv,只是 \(110pts,rk124\)。 T1 这道题是签到题,显然不用说。 T2 这道题比较难想。 我们先考虑这个给的数据范围啥意思。 \(2e5\) 大概率是 \(\mathcal{O}(n)\) 或 \(\mathcal{O}(n\log n)\)。 然后…

记录一下 WPF进程 SendMessage 发送窗口消息进行进程间通信,存在进程权限无法接受消息的问题

前言 最近在接手一个前同事写的WPF项目,是使用.NetFramwork 开发的,使用的进程间通信没有使用我们之前封装的基于WebSocket的封装组件的,而是使用Win32的方式:发送端用的Windows Api:SendMessage ,接受端使用的是…

kettle插件-dm数据库插件,解决kettle9.X版本无法连接数据库资源库问题

场景: 上周四一位小伙伴发出求助,周末有时间一起看下如何解决此问题,信息如下: 用 pdi(kettle)9.2 和 9.4 连接达梦资源库,达梦数据库信息和资源库登录的账密信息一模一样 但是 9.2 可以登录,9.4 一直就是登…

QT6中QGraphicsView特性与应用

QT6中QGraphicsView特性与应用2025-10-12 22:57 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !importan…

2025年10月武汉防水公司TOP5权威推荐榜:专业施工与优质服务的行业

随着建筑行业的快速发展,防水工程在各类建筑项目中的重要性日益凸显。优质的防水工程不仅能有效延长建筑物的使用寿命,还能显著提升居住和使用的舒适度。为了帮助筛选防水公司品牌,特此发布权威推荐榜单,为采购决策…

2025开发区婚纱照公司最新权威推荐榜:创意拍摄与贴心服务的

2025开发区婚纱照公司最新权威推荐榜:创意拍摄与贴心服务的随着婚庆市场的不断发展,越来越多的新人们开始重视婚纱照的质量和创意。为了帮助筛选婚纱照品牌,特此发布权威推荐榜单,为采购决策提供专业参考价值。本文…

用户交互scanner方法学习及使用示例

Scanner的next方法 调用方法前 一般先通过scanner.hasNext()来判断用户是否有输入 流程 首先,next方法只有读取到有效字符才结束等待输入 之后,自动去掉有效字符前面的空白(因此,用户在有效字符前输入的空白不会被…