Skip to content

Commit

Permalink
fix: 修复 form stream 失效问题 (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 authored Jun 5, 2024
1 parent 71c3608 commit 47120c6
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 12 deletions.
11 changes: 11 additions & 0 deletions src/AlipayFormStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// import { statSync } from 'node:fs';
import FormStream from 'formstream';

export class AlipayFormStream extends FormStream {
// 覆盖 file 方法,由于 OpenAPI 文件上传需要强制设置 content-length,所以需要增加一次同步文件 io 来实现此功能
// https://github.com/node-modules/formstream/blob/master/lib/formstream.js#L119
// file(name: string, filepath: string, filename: string) {
// const size = statSync(filepath).size;
// return super.file(name, filepath, filename, size);
// }
}
15 changes: 7 additions & 8 deletions src/alipay.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { debuglog } from 'node:util';
import { createVerify, randomUUID, createSign } from 'node:crypto';
import { Readable } from 'node:stream';
import urllib, { Agent } from 'urllib';
import type {
HttpClientResponse, HttpMethod, RequestOptions, RawResponseWithMeta,
} from 'urllib';
import camelcaseKeys from 'camelcase-keys';
import snakeCaseKeys from 'snakecase-keys';
import FormStream from 'formstream';
import { Stream as SSEStream } from 'sse-decoder';
import { AlipayFormStream } from './AlipayFormStream.js';
import type { AlipaySdkConfig } from './types.js';
import { AlipayFormData } from './form.js';
import {
Expand All @@ -17,8 +18,6 @@ import {
} from './util.js';
import { getSNFromPath, getSN, loadPublicKey, loadPublicKeyFromPath } from './antcertutil.js';

export const AlipayFormStream = FormStream;

const debug = debuglog('alipay-sdk');
const http2Agent = new Agent({
allowH2: true,
Expand Down Expand Up @@ -142,7 +141,7 @@ export interface AlipayCURLOptions {
/** 参数需在请求 JSON 传参 */
body?: Record<string, any>;
/** 表单方式提交数据 */
form?: AlipayFormData | FormStream;
form?: AlipayFormData | AlipayFormStream;
/** 调用方的 requestId,用于定位一次请求,需要每次请求保持唯一 */
requestId?: string;
/**
Expand Down Expand Up @@ -357,9 +356,9 @@ export class AlipaySdk {
throw new TypeError('提交 form 数据不支持内容加密');
}
// 文件上传,走 multipart/form-data
let form: FormStream;
let form: AlipayFormStream;
if (options.form instanceof AlipayFormData) {
form = new FormStream();
form = new AlipayFormStream();
const dataFieldValue = {} as Record<string, string | object>;
for (const item of options.form.fields) {
dataFieldValue[item.name] = item.value;
Expand All @@ -372,7 +371,7 @@ export class AlipaySdk {
form.field('data', httpRequestBody, 'application/json');
// 文件上传 https://opendocs.alipay.com/open-v3/054oog#%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0
for (const item of options.form.files) {
form.file(item.name, item.path, item.fieldName);
form.file(item.fieldName, item.path, item.name);
}
} else if (options.form instanceof AlipayFormStream) {
form = options.form;
Expand All @@ -384,7 +383,7 @@ export class AlipaySdk {
} else {
throw new TypeError('options.form 必须是 AlipayFormData 或者 AlipayFormStream 类型');
}
requestOptions.content = form as any;
requestOptions.content = new Readable().wrap(form as any);
Object.assign(requestOptions.headers, form.headers());
} else {
// 普通请求
Expand Down
3 changes: 3 additions & 0 deletions src/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ function isJSONString(value: any) {
}

export interface IFile {
/** 文件名 */
name: string;
/** 文件路径 */
path: string;
/** 表单字段名 */
fieldName: string;
}

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './types.js';
export * from './alipay.js';
export { AlipayFormData } from './form.js';
export { AlipayFormStream } from './AlipayFormStream.js';
28 changes: 24 additions & 4 deletions test/alipay.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe('test/alipay.test.ts', () => {
});
});

it.skip('POST 文件上传,使用 AlipayFormData', async () => {
it('POST 文件上传,使用 AlipayFormData', async () => {
// https://opendocs.alipay.com/open-v3/5aa91070_alipay.open.file.upload?scene=common&pathHash=c8e11ccc
const filePath = getFixturesFile('demo.jpg');
const form = new AlipayFormData();
Expand All @@ -146,11 +146,11 @@ describe('test/alipay.test.ts', () => {
assert(uploadResult.traceId);
});

it.skip('POST 文件上传,使用 AlipayFormData with body', async () => {
it('POST 文件上传,使用 AlipayFormData with body', async () => {
// https://opendocs.alipay.com/open-v3/5aa91070_alipay.open.file.upload?scene=common&pathHash=c8e11ccc
const filePath = getFixturesFile('demo.jpg');
const form = new AlipayFormData();
form.addFile('file_content', '图片.jpg', filePath);
form.addFile('file_content', 'demo.jpg', filePath);

const uploadResult = await sdkStable.curl<{
file_id: string;
Expand Down Expand Up @@ -466,7 +466,7 @@ describe('test/alipay.test.ts', () => {
aesDecryptText(readFixturesFile('test_alipayCertPublicKey_RSA2_aesEncryptText.crt'), encryptKey),
});

it.skip('POST 文件上传,使用 AlipayFormStream with body', async () => {
it('POST 文件上传,使用 AlipayFormStream with body', async () => {
// https://opendocs.alipay.com/open-v3/5aa91070_alipay.open.file.upload?scene=common&pathHash=c8e11ccc
const filePath = getFixturesFile('demo.jpg');
const form = new AlipayFormStream();
Expand All @@ -486,6 +486,26 @@ describe('test/alipay.test.ts', () => {
assert(uploadResult.traceId);
});

it('POST 文件上传,使用 AlipayFormData with body', async () => {
// https://opendocs.alipay.com/open-v3/5aa91070_alipay.open.file.upload?scene=common&pathHash=c8e11ccc
const filePath = getFixturesFile('demo.jpg');
const form = new AlipayFormData();
form.addFile('file_content', '图片.jpg', filePath);

const uploadResult = await sdk.curl<{
file_id: string;
}>('POST', '/v3/alipay/open/file/upload', {
form,
body: {
biz_code: 'openpt_appstore',
},
});
console.log(uploadResult);
assert(uploadResult.data.file_id);
assert.equal(uploadResult.responseHttpStatus, 200);
assert(uploadResult.traceId);
});

it('POST /v3/alipay/user/deloauth/detail/query', async () => {
// https://opendocs.alipay.com/open-v3/668cd27c_alipay.user.deloauth.detail.query?pathHash=3ab93168
const result = await sdk.curl('POST', '/v3/alipay/user/deloauth/detail/query', {
Expand Down

0 comments on commit 47120c6

Please sign in to comment.