co.elastic.clients.transport.TransportException:[es/search] 缺少 [X-Elastic-Product] 标头

Isv*_*rei 17 java elasticsearch

我在这里关注弹性搜索 java api 客户端的教程: https: //www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/connecting.html

我的代码如下。

// Create the low-level client
RestClient restClient = RestClient.builder(
 new HttpHost("localhost", 9200)).build();

// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
 restClient, new JacksonJsonpMapper());

// And create the API client
ElasticsearchClient client = new ElasticsearchClient(transport);

try {
 SearchResponse<Object> search = client.search(s -> s
   .index("*:*"),
   Object.class);
} catch (IOException e) {
 System.out.println(e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)

这段代码抛出以下异常:

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.
Run Code Online (Sandbox Code Playgroud)

我尝试通过setDefaultHeaders如下方法手动放置此标头:

RestClientBuilder builder = RestClient.builder(
 new HttpHost("localhost", 9200, "http"));
Header[] defaultHeaders = new Header[]{new BasicHeader("X-Elastic-Product", "Elasticsearch")};
builder.setDefaultHeaders(defaultHeaders);
RestClient restClient = builder.build();
Run Code Online (Sandbox Code Playgroud)

但错误是一样的。

我尝试过 7.16 和 8.0.0 版本,结果相同。

mys*_*cks 17

RestClientBuilder允许您指定的默认标头是请求标头,而不是响应标头。您收到的错误是因为较旧的 Elasticsearch [服务器] 版本X-Elastic-Product=Elasticsearch在任何 API 响应中都不包含标头,但最近的发行版包含标头(7.14+?),因此较新版本elasticsearch-java(即客户端)需要它们。

\n

我在同一条船上 \xe2\x80\x94 我使用 8.4.2elasticsearch-java和 Elasticsearch 服务器版本 7.2.0。

\n

我遇到了两个基于格式的兼容性问题:

\n
    \n
  1. 客户端Content-Type向服务器传递未知信息,因此其请求被拒绝并返回 406
  2. \n
  3. 客户端验证响应是否有X-Elastic-Product=Elasticsearch标头
  4. \n
\n

幸运的是,RestClientBuilder允许您通过以下方式自定义底层 http 客户端:setHttpClientConfigCallback。回调看起来像这样,所以基本上您可以拦截请求和响应,操作标头,从而解决这些问题:

\n
    public interface HttpClientConfigCallback {\n        /**\n         * Allows to customize the {@link CloseableHttpAsyncClient} being created and used by the {@link RestClient}.\n         * Commonly used to customize the default {@link org.apache.http.client.CredentialsProvider} for authentication\n         * or the {@link SchemeIOSessionStrategy} for communication through ssl without losing any other useful default\n         * value that the {@link RestClientBuilder} internally sets, like connection pooling.\n         */\n        HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder);\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

具体来说,这对我有用:

\n
var httpClientConfigCallback = httpClientBuilder ->\n        httpClientBuilder\n            .setDefaultCredentialsProvider(credentialsProvider)\n            // this request & response header manipulation helps get around newer (>=7.16) versions\n            // of elasticsearch-java client not working with older (<7.14) versions of Elasticsearch\n            // server\n            .setDefaultHeaders(\n                List.of(\n                    new BasicHeader(\n                        HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())))\n            .addInterceptorLast(\n                (HttpResponseInterceptor)\n                    (response, context) ->\n                        response.addHeader("X-Elastic-Product", "Elasticsearch"));\nvar restClient =\n        RestClient.builder(elasticsearchHosts)\n            .setHttpClientConfigCallback(httpClientConfigCallback)\n            .build();\n\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,上述产品和 API 版本之间仍然可能存在行为差异,因为它们相差太大。以上仅修复了基于格式的不兼容性。因此,最好至少使用这些组件的相同主要版本(即使不是完全相同的版本)。

\n