关于高版本elasticsearch-java请求低版本集群的问题

1,311 阅读2分钟

记录供个人回看,有问题欢迎讨论

依赖版本:

    <!--elastic-search java客户端-->
    <dependency>
        <groupId>co.elastic.clients</groupId>
        <artifactId>elasticsearch-java</artifactId>
        <version>8.15.3</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.17.0</version>
    </dependency>

前置知识

在es8client中,构建es client时可以自定义请求响应拦截器

var restClient = RestClient
        .builder(HttpHost.create("serverUrl"))
        .setDefaultHeaders(new Header[]{
                // ...
        })
        .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                .addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
                    // 请求拦截器逻辑

                })
                .addInterceptorLast((HttpResponseInterceptor) (response, context) -> {
                    // 响应拦截器逻辑

                })
        )
        .build();

问题处理思路

  • 用拦截器编辑请求头和响应头

  • 编辑请求头让es服务器兼容

  • 编辑响应头让es客户端兼容

【兼容性问题一】 Missing [X-Elastic-Product] header(406)

报错信息类似:

co.elastic.clients.transport.TransportException: [es/search] Missing [X-Elastic-Product] header. Please check that you are connecting to an Elasticsearch instance, and that any networking filters are preserving that header.

这个就是响应头缺少"X-Elastic-Product"这个字段,es8客户端会验证响应是否有X-Elastic-Product=Elasticsearch标头

解决方法是编辑响应头:

var restClient = RestClient
        .builder(HttpHost.create(serverUrl))
        .setDefaultHeaders(new Header[]{
          ...
        })
        .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                .setDefaultCredentialsProvider(credentialsProvider)
                .addInterceptorLast((HttpResponseInterceptor)
                        (response, context) ->
                                response.addHeader("X-Elastic-Product", "Elasticsearch"))
        ) // 这部分为了避免旧版本406报错(如果es更新到了8.xx,把这个去掉即可)
        .build();

【兼容性问题2】 Invalid media-type value on headers [Accept, Content-Type]

报错信息类似:

[es/create] failed: [media_type_header_exception] Invalid media-type value on headers [Accept, Content-Type]

这个同上,编辑请求头:

var restClient = RestClient
        .builder(HttpHost.create(serverUrl))
        .setDefaultHeaders(new Header[]{
  
        })
        .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                .setDefaultCredentialsProvider(credentialsProvider)
                .addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
                    // 这里主动编辑请求头,避免兼容性问题报错
                    // 在es8中,默认的请求头 Accept 字段为:
                    // Accept: application/vnd.elasticsearch+json; compatible-with=8
                    // 访问低版本es集群有可能出现
                    // [es/create] failed:
                    // [media_type_header_exception] Invalid media-type value
                    // on headers [Accept, Content-Type]
                    // 通过拦截器编辑请求头以避免此错误!
                    request.setHeader("Accept", "application/json");
                })
        ) // 这部分为了避免旧版本406报错(如果es更新到了8.xx,把这个去掉即可)
        .build();

一个示例


// 账号密码认证 Provider:
var credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(
        username, // 用户名
        password // 密码
));

RestClient restClient = RestClient
        .builder(HttpHost.create(serverUrl))
        .setDefaultHeaders(new Header[]{
                new BasicHeader("Content-Type", "application/json; charset=utf-8"),
                new BasicHeader("Accept", "application/json")
                // 暂时不用token认证
                // new BasicHeader("Authorization", "ApiKey " + apiKey) 
                
        })
        .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                .setDefaultCredentialsProvider(credentialsProvider)
                .addInterceptorFirst((HttpRequestInterceptor) (request,context) -> {

                    // 这里主动编辑请求头,避免兼容性问题报错
                    // 在es8中,默认的请求头 Accept 字段为:
                    // Accept: application/vnd.elasticsearch+json; compatible-with=8
                    // 访问低版本es集群有可能出现
                    // [es/create] failed:
                    // [media_type_header_exception] Invalid media-type value
                    // on headers [Accept, Content-Type]

                    // 通过拦截器编辑请求头以避免此错误!
                    request.setHeader("Accept", "application/json");

                })
                .addInterceptorLast((HttpResponseInterceptor)
                        (response, context) ->
                                response.addHeader("X-Elastic-Product", "Elasticsearch"))
        ) // 这部分为了避免旧版本406报错(如果es更新到了8.xx,把这个去掉即可)
        .build()

参考: