Client.ts は、OpenSearch Industry Algorithm Edition 向けの再利用可能な HTTP クライアントを提供します。これにより、リクエスト署名、認証情報管理、リトライロジック、およびエラー処理が自動的に行われるため、検索機能の構築に集中できます。
前提条件
開始する前に、以下が揃っていることを確認してください。
Node.js と npm がインストールされていること
AccessKey ID と AccessKey Secret を持つ Alibaba Cloud アカウントがあること
ご利用のインスタンスの OpenSearch Industry Algorithm Edition サービスエンドポイント
依存関係のインストール
以下のパッケージを package.json に追加します。npm からインストールしてください。
dependencies — ランタイムで必要:
| パッケージ | 目的 |
|---|---|
@alicloud/credentials | AccessKey および STS トークンリフレッシュを含む Alibaba Cloud 認証情報を管理します |
@alicloud/opensearch-util | OpenSearch リクエストのリクエスト署名を生成し、Content-MD5 を計算します |
@alicloud/tea-typescript | コア HTTP ランタイム: リクエスト実行、リトライ、およびバックオフを処理します |
@alicloud/tea-util | シリアル化、ヘッダー生成、およびレスポンス解析のためのユーティリティ関数 |
devDependencies — TypeScript コンパイルに必要:
| パッケージ | 目的 |
|---|---|
typescript | TypeScript コンパイラ |
ts-node | 個別のコンパイルステップなしで TypeScript ファイルを直接実行します |
Client.ts
Client.ts は、OpenSearch に署名付き HTTP リクエストを構築して送信します。すべてのリクエストは、以下の _request メソッドを介して行われます。
設定された認証情報プロバイダーから認証情報を取得します。
必要なヘッダー (
Date、X-Opensearch-Nonce、Authorization、およびオプションでX-Opensearch-Security-Token) を設定します。リクエストボディの
Content-MD5を計算します。設定可能なリトライおよびバックオフ動作でリクエストを実行します。
解析されたレスポンスボディとヘッダーを返します。または、4xx/5xx 状態コードの場合は例外をスローします。
import OpenSearchUtil from '@alicloud/opensearch-util/dist/client';
import * as $tea from '@alicloud/tea-typescript';
import Util, * as $Util from '@alicloud/tea-util';
import Credential, * as $Credential from '@alicloud/credentials';
import Config from "./Config";
class Client {
_endpoint: string;
_protocol: string;
_userAgent: string;
_credential: Credential;
constructor(config: Config) {
if (Util.isUnset($tea.toMap(config))) {
throw $tea.newError({
name: "ParameterMissing",
message: "'config' can not be unset",
});
}
if (Util.empty(config.type)) {
config.type = "access_key";
}
let credentialConfig = new $Credential.Config({
accessKeyId: config.accessKeyId, // AccessKey ID — load from environment variables, not hardcoded
type: config.type,
accessKeySecret: config.accessKeySecret, // AccessKey Secret — load from environment variables, not hardcoded
securityToken: config.securityToken, // STS security token (required for temporary credentials only)
});
this._credential = new Credential(credentialConfig);
this._endpoint = config.endpoint;
this._protocol = config.protocol;
this._userAgent = config.userAgent;
}
async _request(method: string, pathname: string, query: {[key: string ]: any}, headers: {[key: string ]: string}, body: any, runtime: $Util.RuntimeOptions): Promise<{[key: string ]: any}> {
let _runtime: { [key: string]: any } = {
timeouted: "retry",
readTimeout: runtime.readTimeout,
connectTimeout: runtime.connectTimeout,
httpProxy: runtime.httpProxy,
httpsProxy: runtime.httpsProxy,
noProxy: runtime.noProxy,
maxIdleConns: runtime.maxIdleConns,
retry: {
retryable: runtime.autoretry,
maxAttempts: Util.defaultNumber(runtime.maxAttempts, 3), // default: 3 attempts
},
backoff: {
policy: Util.defaultString(runtime.backoffPolicy, "no"), // default: no backoff
period: Util.defaultNumber(runtime.backoffPeriod, 1),
},
ignoreSSL: runtime.ignoreSSL,
}
let _lastRequest = null;
let _now = Date.now();
let _retryTimes = 0;
while ($tea.allowRetry(_runtime['retry'], _retryTimes, _now)) {
if (_retryTimes > 0) {
let _backoffTime = $tea.getBackoffTime(_runtime['backoff'], _retryTimes);
if (_backoffTime > 0) {
await $tea.sleep(_backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try {
let request_ = new $tea.Request();
let accesskeyId = await this._credential.getAccessKeyId();
let accessKeySecret = await this._credential.getAccessKeySecret();
let securityToken = await this._credential.getSecurityToken();
request_.protocol = Util.defaultString(this._protocol, "HTTP");
request_.method = method;
request_.pathname = pathname;
request_.headers = {
'user-agent': Util.getUserAgent(this._userAgent),
Date: OpenSearchUtil.getDate(),
'Content-Type':'application/json',
host: Util.defaultString(this._endpoint, `opensearch-cn-hangzhou.aliyuncs.com`),
'X-Opensearch-Nonce': Util.getNonce(), // Unique nonce per request to prevent replay attacks
...headers,
};
if (!Util.isUnset(query)) {
request_.query = Util.stringifyMapValue(query);
}
if (!Util.isUnset(securityToken) && securityToken!='') {
request_.headers["X-Opensearch-Security-Token"] = securityToken; // Required for STS temporary credentials
}
if (!Util.isUnset(body)) {
let reqBody = Util.toJSONString(body);
request_.headers["Content-Type"] = "application/json";
request_.headers["Content-MD5"] = OpenSearchUtil.getContentMD5(reqBody); // Integrity check for the request body
request_.body = new $tea.BytesReadable(reqBody);
}
request_.headers["Authorization"] = OpenSearchUtil.getSignature(request_, accesskeyId, accessKeySecret); // HMAC signature for authentication
_lastRequest = request_;
let response_ = await $tea.doAction(request_, _runtime);
let objStr = await Util.readAsString(response_.body);
let obj = Util.parseJSON(objStr);
let res = Util.assertAsMap(obj);
if (Util.is4xx(response_.statusCode) || Util.is5xx(response_.statusCode)) {
throw $tea.newError({
message: response_.statusMessage,
data: objStr,
code: response_.statusCode,
});
}
return {
body: res,
headers: response_.headers,
};
} catch (ex) {
if ($tea.isRetryable(ex)) {
continue;
}
throw ex;
}
}
throw $tea.newUnretryableError(_lastRequest);
}
}
export default Client;ソースコードに accessKeyId や accessKeySecret をハードコードしないでください。偶発的な漏洩を防ぐため、認証情報は環境変数またはシークレットマネージャーからロードしてください。
次のステップ
Clientが期待する構成インターフェイスを定義するためにConfig.tsを実装します。HTTP メソッド、パス、クエリパラメーター、およびリクエストボディを渡して OpenSearch API を呼び出すために
Client._request()を使用します。