83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { CourierApiError } from '../courier.error';
|
|
import { CourierConfigService } from '../courier.config';
|
|
import { buildXiaofeixiaSign } from './xiaofeixia.sign';
|
|
import { XIAOFEIXIA_SUCCESS_CODE } from './xiaofeixia.constants';
|
|
import type { XiaofeixiaApiResponse } from './xiaofeixia.types';
|
|
|
|
type RequestParams = Record<string, string | number | undefined>;
|
|
|
|
@Injectable()
|
|
export class XiaofeixiaClient {
|
|
constructor(private readonly courierConfig: CourierConfigService) {}
|
|
|
|
async request<T>(cmd: string, bizParams: RequestParams): Promise<T> {
|
|
const cfg = this.courierConfig.load().xiaofeixia;
|
|
|
|
if (!cfg.mchId || !cfg.apiKey) {
|
|
throw new CourierApiError(
|
|
'小飞侠商户配置不完整,请设置 XIAOFEIXIA_MCH_ID 与 XIAOFEIXIA_API_KEY',
|
|
'CONFIG_ERROR',
|
|
'XIAOFEIXIA',
|
|
);
|
|
}
|
|
|
|
const baseParams: RequestParams = {
|
|
mchId: cfg.mchId,
|
|
cmd,
|
|
signType: cfg.signType,
|
|
...bizParams,
|
|
};
|
|
|
|
if (cfg.appId) {
|
|
baseParams.appId = cfg.appId;
|
|
}
|
|
|
|
const sign = buildXiaofeixiaSign(baseParams, cfg.apiKey, cfg.signType);
|
|
const body = new URLSearchParams();
|
|
|
|
for (const [key, value] of Object.entries({ ...baseParams, sign })) {
|
|
if (value !== undefined && value !== null && value !== '') {
|
|
body.append(key, String(value));
|
|
}
|
|
}
|
|
|
|
let response: Response;
|
|
try {
|
|
response = await fetch(cfg.apiUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: body.toString(),
|
|
});
|
|
} catch (error) {
|
|
throw new CourierApiError(
|
|
'小飞侠接口网络异常',
|
|
'200000',
|
|
'XIAOFEIXIA',
|
|
error,
|
|
);
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new CourierApiError(
|
|
`小飞侠 HTTP 请求失败: ${response.status}`,
|
|
'200000',
|
|
'XIAOFEIXIA',
|
|
);
|
|
}
|
|
|
|
const payload = (await response.json()) as XiaofeixiaApiResponse<T>;
|
|
|
|
if (payload.code !== XIAOFEIXIA_SUCCESS_CODE) {
|
|
throw new CourierApiError(
|
|
payload.message || '小飞侠接口业务失败',
|
|
payload.code,
|
|
'XIAOFEIXIA',
|
|
payload,
|
|
);
|
|
}
|
|
|
|
return payload.data as T;
|
|
}
|
|
}
|