在引用@opensearch-project/opensearch(这是一个elasticsearch-js 客户端分支)并使用client.helpers.bulk 帮助程序时,我也遇到了这个错误。这与 aws-elasticsearch-connector 一起用于实施 AWS SigV4 签名的 API 请求。
错误信息如下:
TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.
at node_modules/@opensearch-project/opensearch/lib/Helpers.js:704:93
这很烦人,而且我没有心情实现自己的 OpenSearch 客户端并直接与 API 交互,所以我深入挖掘并发现了问题。
如何重现错误?
我创建了一个独立的测试来说明问题。希望通过这种方式可以轻松重现。
import { Client } from '@opensearch-project/opensearch';
import * as AWS from 'aws-sdk';
// My fork of https://www.npmjs.com/package/aws-elasticsearch-connector capable of signing requests to AWS OpenSearch
// @opensearch-project/opensearch is not yet capable of signing AWS requests
const createAwsElasticsearchConnector = require('../modules/aws-oss-connector');
const domain =
'PUT_YOUR_DOMAIN_URL_HERE.es.amazonaws.com';
const index = 'YOUR_TEST_INDEX_NAME';
const bootstrapOSSClient = (): Client => {
const ossConnectorConfig = createAwsElasticsearchConnector(AWS.config);
const client = new Client({
...ossConnectorConfig,
node: `https://${domain}`,
});
return client;
};
const main = async (): Promise<void> => {
try {
console.info('Starting processing');
// TEST DEFINITION
const input = [
{ id: '1', name: 'test' },
{ id: '2', name: 'test 2' },
];
const client = bootstrapOSSClient();
const response = await client.helpers.bulk({
datasource: input,
onDocument(doc: any) {
console.info(`Processing document #${doc.id}`);
return {
index: { _index: index, _id: doc.id },
};
},
});
console.info(`Indexed ${response.successful} documents`);
// END TEST DEFINITION
console.info('Finished processing');
} catch (error) {
console.warn(`Error in main(): ${error}`);
}
};
try {
main().then(() => {
console.info('Exited main()');
});
} catch (error) {
console.warn(`Top-level error: ${error}`);
}
结果是
$ npx ts-node ./.vscode/test.ts
Starting processing
Processing document #1
Processing document #2
(node:39232) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.
at D:\Development\eSUB\Coronado\git\platform\node_modules\@opensearch-project\opensearch\lib\Helpers.js:704:93
(Use `node --trace-warnings ...` to show where the warning was created)
(node:39232) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:39232) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Indexed 2 documents
Finished processing
Exited main()
单步执行代码我能够拦截对node_modules/@opensearch-project/opensearch/lib/Helpers.js:704:93 where 的单个调用
-
client.bulk() 被调用
- 在
\opensearch\api\api\bulk.js中调用bulkApi()并成功返回
-
await finish() 在 \opensearch\lib\Helpers.js:559 中被调用
- 在
\opensearch\lib\Transport.js 内部调用prepareRequest(),以return transportReturn 结束
- 这最终以
request():177 调用
return p.then(onFulfilled, onRejected)
当时p 是null。这导致我在 AWS Transport 类中的回调负责签署请求以回调到带有未定义第二个参数的 Helper.js tryBulk(),从而导致 Cannot destructure property 'body' 错误。
预期的行为是什么?
Transport.js 在request() call 中传递回调时,请求的实现显然不会导致null p 承诺问题。我在opensearch-js 存储库中记录了bug。
解决方法
至少对我来说,这看起来只有在使用自定义 AWS 签名请求连接器实施时才会出现问题。如果您的情况类似,一个快速的解决方法是修改该实现Transport 类。这是一个特定于aws-elasticsearch-connector 的快速而肮脏的修补程序。
你需要修改AmazonTransport.js from
class AmazonTransport extends Transport {
request (params, options = {}, callback = undefined) {
...
// Callback support
awaitAwsCredentials(awsConfig)
.then(() => super.request(params, options, callback))
.catch(callback)
}
到
// Callback support
// Removed .then() chain due to a bug https://github.com/opensearch-project/opensearch-js/issues/185
// .then() was calling then (onFulfilled, onRejected) on transportReturn, resulting in a null value exception
awaitAwsCredentials(awsConfig).then();
try {
super.request(params, options, callback);
} catch (err) {
callback(err, { body: null });
}