@ticatec/restful_service_api 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-CN.md +72 -43
- package/README.md +56 -27
- package/dist/RestService.d.ts +21 -13
- package/package.json +1 -1
package/README-CN.md
CHANGED
|
@@ -29,14 +29,14 @@ import RestService from '@ticatec/restful_service_api';
|
|
|
29
29
|
|
|
30
30
|
// 实现 RestService 接口
|
|
31
31
|
class MyApiClient implements RestService {
|
|
32
|
-
async get(url: string, params?: any) {
|
|
32
|
+
async get(url: string, params?: any, dataProcessor?: DataProcessor) {
|
|
33
33
|
// 在这里实现
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
async post(url: string, data
|
|
35
|
+
|
|
36
|
+
async post(url: string, data?: any, options?: RestfulOptions) {
|
|
37
37
|
// 在这里实现
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
// ... 其他方法
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -56,9 +56,9 @@ const newUser = await api.post('/users', { name: '张三' });
|
|
|
56
56
|
```typescript
|
|
57
57
|
interface RestService {
|
|
58
58
|
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
59
|
-
post(url: string, data
|
|
60
|
-
put(url: string, data
|
|
61
|
-
del(url: string, data
|
|
59
|
+
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
60
|
+
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
61
|
+
del(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
62
62
|
upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
|
|
63
63
|
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
|
|
64
64
|
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
|
|
@@ -72,18 +72,27 @@ interface RestService {
|
|
|
72
72
|
- **params**: 查询参数(可选)
|
|
73
73
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
74
74
|
|
|
75
|
-
#### `post(url, data
|
|
75
|
+
#### `post(url, data?, options?)`
|
|
76
76
|
- **url**: 接口端点 URL
|
|
77
|
-
- **data**:
|
|
78
|
-
- **
|
|
79
|
-
- **
|
|
80
|
-
- **
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
- **data**: 请求载荷(可选)
|
|
78
|
+
- **options**: 可选的配置对象,包含:
|
|
79
|
+
- **params**: 查询参数(可选)
|
|
80
|
+
- **contentType**: Content-Type 请求头(可选,默认为 application/json)
|
|
81
|
+
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
82
|
+
|
|
83
|
+
#### `put(url, data?, options?)`
|
|
84
|
+
类似于 POST,但用于更新操作。所有参数均为可选。
|
|
85
|
+
- **options**: 可选的配置对象,包含:
|
|
86
|
+
- **params**: 查询参数(可选)
|
|
87
|
+
- **contentType**: Content-Type 请求头(可选,默认为 application/json)
|
|
88
|
+
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
89
|
+
|
|
90
|
+
#### `del(url, data?, options?)`
|
|
86
91
|
用于删除操作,支持可选的请求体。
|
|
92
|
+
- **options**: 可选的配置对象,包含:
|
|
93
|
+
- **params**: 查询参数(可选)
|
|
94
|
+
- **contentType**: Content-Type 请求头(可选,默认为 application/json)
|
|
95
|
+
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
87
96
|
|
|
88
97
|
#### `upload(url, params, file, fileKey?, dataProcessor?)`
|
|
89
98
|
- **url**: 上传端点 URL
|
|
@@ -128,13 +137,21 @@ try {
|
|
|
128
137
|
### 类型和拦截器
|
|
129
138
|
|
|
130
139
|
```typescript
|
|
131
|
-
import {
|
|
132
|
-
PreInterceptor,
|
|
133
|
-
PostInterceptor,
|
|
134
|
-
ErrorHandler,
|
|
135
|
-
DataProcessor
|
|
140
|
+
import {
|
|
141
|
+
PreInterceptor,
|
|
142
|
+
PostInterceptor,
|
|
143
|
+
ErrorHandler,
|
|
144
|
+
DataProcessor,
|
|
145
|
+
RestfulOptions
|
|
136
146
|
} from '@ticatec/restful_service_api';
|
|
137
147
|
|
|
148
|
+
// RestfulOptions 用于配置请求
|
|
149
|
+
const options: RestfulOptions = {
|
|
150
|
+
params: { page: 1, limit: 10 },
|
|
151
|
+
contentType: 'application/json',
|
|
152
|
+
dataProcessor: (data: any) => data.results || data
|
|
153
|
+
};
|
|
154
|
+
|
|
138
155
|
// 请求前拦截器,用于添加认证头
|
|
139
156
|
const preInterceptor: PreInterceptor = (method: string, url: string) => {
|
|
140
157
|
return {
|
|
@@ -170,15 +187,15 @@ const dataProcessor: DataProcessor = (data: any) => {
|
|
|
170
187
|
预定义的内容类型常量:
|
|
171
188
|
|
|
172
189
|
```typescript
|
|
173
|
-
import {
|
|
190
|
+
import {
|
|
174
191
|
CONTENT_TYPE_NAME,
|
|
175
192
|
TYPE_JSON,
|
|
176
193
|
TYPE_HTML,
|
|
177
|
-
TYPE_TEXT
|
|
194
|
+
TYPE_TEXT
|
|
178
195
|
} from '@ticatec/restful_service_api';
|
|
179
196
|
|
|
180
197
|
// 使用示例
|
|
181
|
-
await api.post('/upload', data, {}, TYPE_JSON);
|
|
198
|
+
await api.post('/upload', data, {}, { contentType: TYPE_JSON });
|
|
182
199
|
```
|
|
183
200
|
|
|
184
201
|
## 实现示例
|
|
@@ -186,11 +203,12 @@ await api.post('/upload', data, {}, TYPE_JSON);
|
|
|
186
203
|
以下是使用原生 fetch API 的完整实现示例:
|
|
187
204
|
|
|
188
205
|
```typescript
|
|
189
|
-
import RestService, {
|
|
190
|
-
ApiError,
|
|
191
|
-
PreInterceptor,
|
|
206
|
+
import RestService, {
|
|
207
|
+
ApiError,
|
|
208
|
+
PreInterceptor,
|
|
192
209
|
PostInterceptor,
|
|
193
|
-
|
|
210
|
+
RestfulOptions,
|
|
211
|
+
TYPE_JSON
|
|
194
212
|
} from '@ticatec/restful_service_api';
|
|
195
213
|
|
|
196
214
|
class FetchRestService implements RestService {
|
|
@@ -209,24 +227,33 @@ class FetchRestService implements RestService {
|
|
|
209
227
|
return this.request('GET', url + queryString, null, undefined, dataProcessor);
|
|
210
228
|
}
|
|
211
229
|
|
|
212
|
-
async post(url: string, data
|
|
213
|
-
|
|
230
|
+
async post(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
231
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
232
|
+
const params = options?.params;
|
|
233
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
234
|
+
return this.request('POST', url + queryString, data, contentType, options?.dataProcessor);
|
|
214
235
|
}
|
|
215
236
|
|
|
216
|
-
async put(url: string, data
|
|
217
|
-
|
|
237
|
+
async put(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
238
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
239
|
+
const params = options?.params;
|
|
240
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
241
|
+
return this.request('PUT', url + queryString, data, contentType, options?.dataProcessor);
|
|
218
242
|
}
|
|
219
243
|
|
|
220
|
-
async del(url: string, data
|
|
221
|
-
|
|
244
|
+
async del(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
245
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
246
|
+
const params = options?.params;
|
|
247
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
248
|
+
return this.request('DELETE', url + queryString, data, contentType, options?.dataProcessor);
|
|
222
249
|
}
|
|
223
250
|
|
|
224
251
|
private async request(method: string, url: string, body?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any> {
|
|
225
252
|
const fullUrl = this.baseURL + url;
|
|
226
|
-
|
|
253
|
+
|
|
227
254
|
// 应用请求前拦截器
|
|
228
255
|
const interceptorResult = this.preInterceptor?.(method, fullUrl) || { headers: {} };
|
|
229
|
-
|
|
256
|
+
|
|
230
257
|
const headers = {
|
|
231
258
|
...interceptorResult.headers,
|
|
232
259
|
...(contentType && { 'Content-Type': contentType })
|
|
@@ -245,19 +272,19 @@ class FetchRestService implements RestService {
|
|
|
245
272
|
throw new ApiError(response.status, errorData);
|
|
246
273
|
}
|
|
247
274
|
|
|
248
|
-
let
|
|
249
|
-
|
|
275
|
+
let responseData = await response.json();
|
|
276
|
+
|
|
250
277
|
// 应用响应后拦截器
|
|
251
278
|
if (this.postInterceptor) {
|
|
252
|
-
|
|
279
|
+
responseData = await this.postInterceptor(responseData);
|
|
253
280
|
}
|
|
254
|
-
|
|
281
|
+
|
|
255
282
|
// 应用数据处理器
|
|
256
283
|
if (dataProcessor) {
|
|
257
|
-
|
|
284
|
+
responseData = dataProcessor(responseData);
|
|
258
285
|
}
|
|
259
286
|
|
|
260
|
-
return
|
|
287
|
+
return responseData;
|
|
261
288
|
} catch (error) {
|
|
262
289
|
if (error instanceof ApiError) {
|
|
263
290
|
throw error;
|
|
@@ -270,6 +297,8 @@ class FetchRestService implements RestService {
|
|
|
270
297
|
// 使用示例
|
|
271
298
|
const api = new FetchRestService('https://api.example.com');
|
|
272
299
|
const users = await api.get('/users');
|
|
300
|
+
const newUser = await api.post('/users', { name: '张三' });
|
|
301
|
+
const updatedUser = await api.put('/users/1', { name: '李四' });
|
|
273
302
|
```
|
|
274
303
|
|
|
275
304
|
### 文件上传和下载示例
|
package/README.md
CHANGED
|
@@ -29,11 +29,11 @@ import RestService from '@ticatec/restful_service_api';
|
|
|
29
29
|
|
|
30
30
|
// Your implementation of RestService interface
|
|
31
31
|
class MyApiClient implements RestService {
|
|
32
|
-
async get(url: string, params?: any) {
|
|
32
|
+
async get(url: string, params?: any, dataProcessor?: DataProcessor) {
|
|
33
33
|
// Implementation here
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
async post(url: string, data
|
|
36
|
+
async post(url: string, data?: any, options?: RestfulOptions) {
|
|
37
37
|
// Implementation here
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -56,9 +56,9 @@ The main interface that defines the contract for REST operations:
|
|
|
56
56
|
```typescript
|
|
57
57
|
interface RestService {
|
|
58
58
|
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
59
|
-
post(url: string, data
|
|
60
|
-
put(url: string, data
|
|
61
|
-
del(url: string, data
|
|
59
|
+
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
60
|
+
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
61
|
+
del(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
62
62
|
upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
|
|
63
63
|
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
|
|
64
64
|
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
|
|
@@ -72,18 +72,27 @@ interface RestService {
|
|
|
72
72
|
- **params**: Query parameters (optional)
|
|
73
73
|
- **dataProcessor**: Function to process response data (optional)
|
|
74
74
|
|
|
75
|
-
#### `post(url, data
|
|
75
|
+
#### `post(url, data?, options?)`
|
|
76
76
|
- **url**: The endpoint URL
|
|
77
|
-
- **data**: Request payload
|
|
78
|
-
- **
|
|
79
|
-
- **
|
|
80
|
-
- **
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
- **data**: Request payload (optional)
|
|
78
|
+
- **options**: Optional configuration object containing:
|
|
79
|
+
- **params**: Query parameters (optional)
|
|
80
|
+
- **contentType**: Content-Type header (optional, defaults to application/json)
|
|
81
|
+
- **dataProcessor**: Function to process response data (optional)
|
|
82
|
+
|
|
83
|
+
#### `put(url, data?, options?)`
|
|
84
|
+
Similar to POST but for update operations. All parameters are optional.
|
|
85
|
+
- **options**: Optional configuration object containing:
|
|
86
|
+
- **params**: Query parameters (optional)
|
|
87
|
+
- **contentType**: Content-Type header (optional, defaults to application/json)
|
|
88
|
+
- **dataProcessor**: Function to process response data (optional)
|
|
89
|
+
|
|
90
|
+
#### `del(url, data?, options?)`
|
|
86
91
|
For delete operations with optional request body.
|
|
92
|
+
- **options**: Optional configuration object containing:
|
|
93
|
+
- **params**: Query parameters (optional)
|
|
94
|
+
- **contentType**: Content-Type header (optional, defaults to application/json)
|
|
95
|
+
- **dataProcessor**: Function to process response data (optional)
|
|
87
96
|
|
|
88
97
|
#### `upload(url, params, file, fileKey?, dataProcessor?)`
|
|
89
98
|
- **url**: The upload endpoint URL
|
|
@@ -132,9 +141,17 @@ import {
|
|
|
132
141
|
PreInterceptor,
|
|
133
142
|
PostInterceptor,
|
|
134
143
|
ErrorHandler,
|
|
135
|
-
DataProcessor
|
|
144
|
+
DataProcessor,
|
|
145
|
+
RestfulOptions
|
|
136
146
|
} from '@ticatec/restful_service_api';
|
|
137
147
|
|
|
148
|
+
// RestfulOptions for configuring requests
|
|
149
|
+
const options: RestfulOptions = {
|
|
150
|
+
params: { page: 1, limit: 10 },
|
|
151
|
+
contentType: 'application/json',
|
|
152
|
+
dataProcessor: (data: any) => data.results || data
|
|
153
|
+
};
|
|
154
|
+
|
|
138
155
|
// Pre-interceptor for adding authentication headers
|
|
139
156
|
const preInterceptor: PreInterceptor = (method: string, url: string) => {
|
|
140
157
|
return {
|
|
@@ -178,7 +195,7 @@ import {
|
|
|
178
195
|
} from '@ticatec/restful_service_api';
|
|
179
196
|
|
|
180
197
|
// Usage
|
|
181
|
-
await api.post('/upload', data, {}, TYPE_JSON);
|
|
198
|
+
await api.post('/upload', data, {}, { contentType: TYPE_JSON });
|
|
182
199
|
```
|
|
183
200
|
|
|
184
201
|
## Implementation Example
|
|
@@ -190,6 +207,7 @@ import RestService, {
|
|
|
190
207
|
ApiError,
|
|
191
208
|
PreInterceptor,
|
|
192
209
|
PostInterceptor,
|
|
210
|
+
RestfulOptions,
|
|
193
211
|
TYPE_JSON
|
|
194
212
|
} from '@ticatec/restful_service_api';
|
|
195
213
|
|
|
@@ -209,16 +227,25 @@ class FetchRestService implements RestService {
|
|
|
209
227
|
return this.request('GET', url + queryString, null, undefined, dataProcessor);
|
|
210
228
|
}
|
|
211
229
|
|
|
212
|
-
async post(url: string, data
|
|
213
|
-
|
|
230
|
+
async post(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
231
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
232
|
+
const params = options?.params;
|
|
233
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
234
|
+
return this.request('POST', url + queryString, data, contentType, options?.dataProcessor);
|
|
214
235
|
}
|
|
215
236
|
|
|
216
|
-
async put(url: string, data
|
|
217
|
-
|
|
237
|
+
async put(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
238
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
239
|
+
const params = options?.params;
|
|
240
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
241
|
+
return this.request('PUT', url + queryString, data, contentType, options?.dataProcessor);
|
|
218
242
|
}
|
|
219
243
|
|
|
220
|
-
async del(url: string, data
|
|
221
|
-
|
|
244
|
+
async del(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
245
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
246
|
+
const params = options?.params;
|
|
247
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
248
|
+
return this.request('DELETE', url + queryString, data, contentType, options?.dataProcessor);
|
|
222
249
|
}
|
|
223
250
|
|
|
224
251
|
private async request(method: string, url: string, body?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any> {
|
|
@@ -245,19 +272,19 @@ class FetchRestService implements RestService {
|
|
|
245
272
|
throw new ApiError(response.status, errorData);
|
|
246
273
|
}
|
|
247
274
|
|
|
248
|
-
let
|
|
275
|
+
let responseData = await response.json();
|
|
249
276
|
|
|
250
277
|
// Apply post-interceptor
|
|
251
278
|
if (this.postInterceptor) {
|
|
252
|
-
|
|
279
|
+
responseData = await this.postInterceptor(responseData);
|
|
253
280
|
}
|
|
254
281
|
|
|
255
282
|
// Apply data processor
|
|
256
283
|
if (dataProcessor) {
|
|
257
|
-
|
|
284
|
+
responseData = dataProcessor(responseData);
|
|
258
285
|
}
|
|
259
286
|
|
|
260
|
-
return
|
|
287
|
+
return responseData;
|
|
261
288
|
} catch (error) {
|
|
262
289
|
if (error instanceof ApiError) {
|
|
263
290
|
throw error;
|
|
@@ -270,6 +297,8 @@ class FetchRestService implements RestService {
|
|
|
270
297
|
// Usage
|
|
271
298
|
const api = new FetchRestService('https://api.example.com');
|
|
272
299
|
const users = await api.get('/users');
|
|
300
|
+
const newUser = await api.post('/users', { name: 'John Doe' });
|
|
301
|
+
const updatedUser = await api.put('/users/1', { name: 'Jane Doe' });
|
|
273
302
|
```
|
|
274
303
|
|
|
275
304
|
### File Upload and Download Examples
|
package/dist/RestService.d.ts
CHANGED
|
@@ -13,6 +13,20 @@ export type DataProcessor = (data: any) => any;
|
|
|
13
13
|
export type PreInterceptor = (method: string, url: string) => PreInterceptorResult;
|
|
14
14
|
export type PostInterceptor = (data: any) => Promise<any>;
|
|
15
15
|
export type ErrorHandler = (ex: Error) => boolean;
|
|
16
|
+
export type RestfulOptions = {
|
|
17
|
+
/**
|
|
18
|
+
* 可选的Content-Type头部,默认为application/json
|
|
19
|
+
*/
|
|
20
|
+
contentType?: string;
|
|
21
|
+
/**
|
|
22
|
+
* 可选的数据处理函数,用于在返回前转换响应数据
|
|
23
|
+
*/
|
|
24
|
+
dataProcessor?: DataProcessor;
|
|
25
|
+
/**
|
|
26
|
+
* 可选的查询参数对象,将被转换为URL查询字符串
|
|
27
|
+
*/
|
|
28
|
+
params?: any;
|
|
29
|
+
};
|
|
16
30
|
export declare const CONTENT_TYPE_NAME = "Content-Type";
|
|
17
31
|
export declare const TYPE_JSON = "application/json";
|
|
18
32
|
export declare const TYPE_HTML = "text/html";
|
|
@@ -30,32 +44,26 @@ export default interface RestService {
|
|
|
30
44
|
* 执行HTTP POST请求创建新资源
|
|
31
45
|
* @param url 请求的目标URL路径
|
|
32
46
|
* @param data 要发送的请求体数据,通常为对象或字符串
|
|
33
|
-
* @param
|
|
34
|
-
* @param contentType 可选的Content-Type头部,默认为application/json
|
|
35
|
-
* @param dataProcessor 可选的数据处理函数,用于在返回前转换响应数据
|
|
47
|
+
* @param options 可选的请求配置选项,包含contentType和dataProcessor
|
|
36
48
|
* @returns 返回Promise,解析为服务器响应数据
|
|
37
49
|
*/
|
|
38
|
-
post(url: string, data
|
|
50
|
+
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
39
51
|
/**
|
|
40
52
|
* 执行HTTP PUT请求更新现有资源
|
|
41
53
|
* @param url 请求的目标URL路径
|
|
42
|
-
* @param data
|
|
43
|
-
* @param
|
|
44
|
-
* @param contentType 可选的Content-Type头部,默认为application/json
|
|
45
|
-
* @param dataProcessor 可选的数据处理函数,用于在返回前转换响应数据
|
|
54
|
+
* @param data 可选的要发送的请求体数据,用于更新资源
|
|
55
|
+
* @param options 可选的请求配置选项,包含contentType和dataProcessor
|
|
46
56
|
* @returns 返回Promise,解析为服务器响应数据
|
|
47
57
|
*/
|
|
48
|
-
put(url: string, data
|
|
58
|
+
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
49
59
|
/**
|
|
50
60
|
* 执行HTTP DELETE请求删除资源
|
|
51
61
|
* @param url 请求的目标URL路径
|
|
52
62
|
* @param data 可选的请求体数据,某些DELETE操作可能需要发送数据
|
|
53
|
-
* @param
|
|
54
|
-
* @param contentType 可选的Content-Type头部,默认为application/json
|
|
55
|
-
* @param dataProcessor 可选的数据处理函数,用于在返回前转换响应数据
|
|
63
|
+
* @param options 可选的请求配置选项,包含contentType和dataProcessor
|
|
56
64
|
* @returns 返回Promise,解析为服务器响应数据
|
|
57
65
|
*/
|
|
58
|
-
del(url: string, data?: any,
|
|
66
|
+
del(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
59
67
|
/**
|
|
60
68
|
* 执行同步文件上传操作
|
|
61
69
|
* @param url 上传的目标URL路径
|
package/package.json
CHANGED