request-iframe 0.0.3 → 0.0.4
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/QUICKSTART.CN.md +35 -8
- package/QUICKSTART.md +35 -8
- package/README.CN.md +170 -24
- package/README.md +230 -19
- package/library/__tests__/coverage-branches.test.ts +356 -0
- package/library/__tests__/requestIframe.test.ts +1008 -58
- package/library/__tests__/stream.test.ts +46 -15
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +1 -0
- package/library/constants/messages.d.ts +2 -0
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +2 -0
- package/library/core/client-server.d.ts +4 -0
- package/library/core/client-server.d.ts.map +1 -1
- package/library/core/client-server.js +45 -22
- package/library/core/client.d.ts +31 -4
- package/library/core/client.d.ts.map +1 -1
- package/library/core/client.js +471 -284
- package/library/core/request.d.ts +3 -1
- package/library/core/request.d.ts.map +1 -1
- package/library/core/request.js +2 -1
- package/library/core/response.d.ts +26 -4
- package/library/core/response.d.ts.map +1 -1
- package/library/core/response.js +142 -81
- package/library/core/server.d.ts +13 -0
- package/library/core/server.d.ts.map +1 -1
- package/library/core/server.js +211 -6
- package/library/index.d.ts +2 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js +32 -3
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +4 -3
- package/library/stream/index.d.ts +11 -1
- package/library/stream/index.d.ts.map +1 -1
- package/library/stream/index.js +21 -3
- package/library/stream/types.d.ts +2 -2
- package/library/stream/types.d.ts.map +1 -1
- package/library/stream/writable-stream.d.ts +1 -1
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +8 -10
- package/library/types/index.d.ts +26 -4
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/index.d.ts +14 -0
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +99 -1
- package/library/utils/path-match.d.ts +16 -0
- package/library/utils/path-match.d.ts.map +1 -1
- package/library/utils/path-match.js +65 -0
- package/package.json +2 -1
- package/react/library/__tests__/index.test.tsx +44 -22
- package/react/library/index.d.ts.map +1 -1
- package/react/library/index.js +81 -23
- package/react/package.json +7 -0
package/QUICKSTART.CN.md
CHANGED
|
@@ -172,22 +172,49 @@ server.on('/api/download', async (req, res) => {
|
|
|
172
172
|
|
|
173
173
|
// Client 端
|
|
174
174
|
const response = await client.send('/api/download', {});
|
|
175
|
-
if (response.
|
|
175
|
+
if (response.data instanceof File || response.data instanceof Blob) {
|
|
176
|
+
const file = response.data instanceof File ? response.data : null;
|
|
177
|
+
const fileName = file?.name || 'download';
|
|
178
|
+
|
|
176
179
|
// 创建下载链接
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
{ type: response.fileData.mimeType }
|
|
180
|
-
);
|
|
181
|
-
const url = URL.createObjectURL(blob);
|
|
182
|
-
|
|
180
|
+
const url = URL.createObjectURL(response.data);
|
|
181
|
+
|
|
183
182
|
// 触发下载
|
|
184
183
|
const a = document.createElement('a');
|
|
185
184
|
a.href = url;
|
|
186
|
-
a.download =
|
|
185
|
+
a.download = fileName;
|
|
187
186
|
a.click();
|
|
187
|
+
URL.revokeObjectURL(url);
|
|
188
188
|
}
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
+
### 文件上传(Client → Server)
|
|
192
|
+
|
|
193
|
+
Client 向 Server 发送文件仅走**流式**。默认 `autoResolve: true`,Server 会在进入 handler 前把文件解析成 `File/Blob` 放到 `req.body`。
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Client 端
|
|
197
|
+
const file = new File(['Hello Upload'], 'upload.txt', { type: 'text/plain' });
|
|
198
|
+
await client.send('/api/upload', file); // File/Blob 会自动分发到 sendFile(走流式)
|
|
199
|
+
|
|
200
|
+
// Server 端
|
|
201
|
+
server.on('/api/upload', async (req, res) => {
|
|
202
|
+
const blob = req.body as Blob;
|
|
203
|
+
const text = await blob.text();
|
|
204
|
+
res.send({ ok: true, text });
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 路由参数(req.params)
|
|
209
|
+
|
|
210
|
+
支持 Express 风格的 `:param` 路由参数,解析结果在 `req.params`。
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
server.on('/api/users/:id', (req, res) => {
|
|
214
|
+
res.send({ userId: req.params.id });
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
191
218
|
### 调试模式
|
|
192
219
|
|
|
193
220
|
开启 trace 模式查看详细日志:
|
package/QUICKSTART.md
CHANGED
|
@@ -172,22 +172,49 @@ server.on('/api/download', async (req, res) => {
|
|
|
172
172
|
|
|
173
173
|
// Client side
|
|
174
174
|
const response = await client.send('/api/download', {});
|
|
175
|
-
if (response.
|
|
175
|
+
if (response.data instanceof File || response.data instanceof Blob) {
|
|
176
|
+
const file = response.data instanceof File ? response.data : null;
|
|
177
|
+
const fileName = file?.name || 'download';
|
|
178
|
+
|
|
176
179
|
// Create download link
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
{ type: response.fileData.mimeType }
|
|
180
|
-
);
|
|
181
|
-
const url = URL.createObjectURL(blob);
|
|
182
|
-
|
|
180
|
+
const url = URL.createObjectURL(response.data);
|
|
181
|
+
|
|
183
182
|
// Trigger download
|
|
184
183
|
const a = document.createElement('a');
|
|
185
184
|
a.href = url;
|
|
186
|
-
a.download =
|
|
185
|
+
a.download = fileName;
|
|
187
186
|
a.click();
|
|
187
|
+
URL.revokeObjectURL(url);
|
|
188
188
|
}
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
+
### File Upload (Client → Server)
|
|
192
|
+
|
|
193
|
+
Client sends files via stream only. By default `autoResolve: true`, server will resolve the file to `File/Blob` and put it into `req.body` before calling your handler.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Client side
|
|
197
|
+
const file = new File(['Hello Upload'], 'upload.txt', { type: 'text/plain' });
|
|
198
|
+
await client.send('/api/upload', file); // File/Blob auto-dispatches to sendFile (stream)
|
|
199
|
+
|
|
200
|
+
// Server side
|
|
201
|
+
server.on('/api/upload', async (req, res) => {
|
|
202
|
+
const blob = req.body as Blob;
|
|
203
|
+
const text = await blob.text();
|
|
204
|
+
res.send({ ok: true, text });
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Route Params (req.params)
|
|
209
|
+
|
|
210
|
+
Supports Express-style `:param` route parameters. Extracted parameters are available in `req.params`.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
server.on('/api/users/:id', (req, res) => {
|
|
214
|
+
res.send({ userId: req.params.id });
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
191
218
|
### Debug Mode
|
|
192
219
|
|
|
193
220
|
Enable trace mode to view detailed logs:
|
package/README.CN.md
CHANGED
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
- ⏱️ **智能超时** - 三阶段超时(连接/同步/异步),自动识别长任务
|
|
75
75
|
- 📦 **TypeScript** - 完整的类型定义和智能提示
|
|
76
76
|
- 🔒 **消息隔离** - secretKey 机制避免多实例消息串线
|
|
77
|
-
- 📁 **文件传输** -
|
|
77
|
+
- 📁 **文件传输** - 支持文件通过流方式传输(Client→Server)
|
|
78
78
|
- 🌊 **流式传输** - 支持大文件分块传输,支持异步迭代器
|
|
79
79
|
- 🌍 **多语言** - 错误消息可自定义,便于国际化
|
|
80
80
|
- ✅ **协议版本** - 内置版本控制,便于升级兼容
|
|
@@ -252,7 +252,8 @@ client.send('/api/getData', data, {
|
|
|
252
252
|
const client = requestIframeClient(iframe, { secretKey: 'main-app' });
|
|
253
253
|
|
|
254
254
|
// 获取子应用的用户信息
|
|
255
|
-
const
|
|
255
|
+
const userInfoResponse = await client.send('/api/user/info', {});
|
|
256
|
+
console.log(userInfoResponse.data); // 用户信息数据
|
|
256
257
|
|
|
257
258
|
// 通知子应用更新数据
|
|
258
259
|
await client.send('/api/data/refresh', { timestamp: Date.now() });
|
|
@@ -296,7 +297,8 @@ server.on('/api/data', async (req, res) => {
|
|
|
296
297
|
|
|
297
298
|
// 父页面(跨域)
|
|
298
299
|
const client = requestIframeClient(iframe, { secretKey: 'data-api' });
|
|
299
|
-
const
|
|
300
|
+
const response = await client.send('/api/data', {});
|
|
301
|
+
const data = response.data; // 成功获取跨域数据
|
|
300
302
|
```
|
|
301
303
|
|
|
302
304
|
### 文件预览和下载
|
|
@@ -318,8 +320,8 @@ server.on('/api/processFile', async (req, res) => {
|
|
|
318
320
|
|
|
319
321
|
// 父页面:下载文件
|
|
320
322
|
const response = await client.send('/api/processFile', { fileId: '123' });
|
|
321
|
-
if (response.
|
|
322
|
-
downloadFile(response.
|
|
323
|
+
if (response.data instanceof File || response.data instanceof Blob) {
|
|
324
|
+
downloadFile(response.data);
|
|
323
325
|
}
|
|
324
326
|
```
|
|
325
327
|
|
|
@@ -505,10 +507,12 @@ server.on('/api/logout', (req, res) => {
|
|
|
505
507
|
await client.send('/api/login', { username: 'tom', password: '123' });
|
|
506
508
|
|
|
507
509
|
// Client 端:后续请求 /api/getUserInfo(自动携带 authToken 和 userId)
|
|
508
|
-
const
|
|
510
|
+
const userInfoResponse = await client.send('/api/getUserInfo', {});
|
|
511
|
+
const userInfo = userInfoResponse.data;
|
|
509
512
|
|
|
510
513
|
// Client 端:请求根路径(只携带 userId,因为 authToken 的 path 是 /api)
|
|
511
|
-
const
|
|
514
|
+
const rootResponse = await client.send('/other', {});
|
|
515
|
+
const rootData = rootResponse.data;
|
|
512
516
|
```
|
|
513
517
|
|
|
514
518
|
#### Client Cookie 管理 API
|
|
@@ -583,22 +587,48 @@ server.on('/api/download', async (req, res) => {
|
|
|
583
587
|
|
|
584
588
|
// Client 端接收
|
|
585
589
|
const response = await client.send('/api/download', {});
|
|
586
|
-
if (response.
|
|
587
|
-
const
|
|
590
|
+
if (response.data instanceof File || response.data instanceof Blob) {
|
|
591
|
+
const file = response.data instanceof File ? response.data : null;
|
|
592
|
+
const fileName = file?.name || 'download';
|
|
588
593
|
|
|
589
|
-
//
|
|
590
|
-
const
|
|
591
|
-
const blob = new Blob([binaryString], { type: mimeType });
|
|
592
|
-
|
|
593
|
-
// 下载文件
|
|
594
|
-
const url = URL.createObjectURL(blob);
|
|
594
|
+
// 直接使用 File/Blob 下载文件
|
|
595
|
+
const url = URL.createObjectURL(response.data);
|
|
595
596
|
const a = document.createElement('a');
|
|
596
597
|
a.href = url;
|
|
597
|
-
a.download = fileName
|
|
598
|
+
a.download = fileName;
|
|
598
599
|
a.click();
|
|
600
|
+
URL.revokeObjectURL(url);
|
|
599
601
|
}
|
|
600
602
|
```
|
|
601
603
|
|
|
604
|
+
#### Client → Server(Client 向 Server 发送文件)
|
|
605
|
+
|
|
606
|
+
Client 端发送文件**仅走流式**。使用 `sendFile()`(或直接 `send(path, file)`);Server 端在 `autoResolve: true`(默认)时会把文件自动解析成 `File/Blob` 放到 `req.body`,当 `autoResolve: false` 时则通过 `req.stream` / `req.body` 暴露为 `IframeFileReadableStream`。
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
// Client 端:发送文件(stream,autoResolve 默认 true)
|
|
610
|
+
const file = new File(['Hello Upload'], 'upload.txt', { type: 'text/plain' });
|
|
611
|
+
const response = await client.send('/api/upload', file);
|
|
612
|
+
|
|
613
|
+
// 或显式使用 sendFile
|
|
614
|
+
const blob = new Blob(['binary data'], { type: 'application/octet-stream' });
|
|
615
|
+
const response2 = await client.sendFile('/api/upload', blob, {
|
|
616
|
+
fileName: 'data.bin',
|
|
617
|
+
mimeType: 'application/octet-stream',
|
|
618
|
+
autoResolve: true // 可选,默认 true:Server 在 req.body 里拿到 File/Blob
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// Server 端:接收文件(autoResolve true → req.body 是 File/Blob)
|
|
622
|
+
server.on('/api/upload', async (req, res) => {
|
|
623
|
+
const blob = req.body as Blob; // 如果 client 发送的是 File,这里也可能是 File
|
|
624
|
+
const text = await blob.text();
|
|
625
|
+
console.log('Received file content:', text);
|
|
626
|
+
res.send({ success: true, size: blob.size });
|
|
627
|
+
});
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
**提示**:当 `client.send()` 的 `body` 是 `File/Blob` 时,会自动分发到 `client.sendFile()`(走流式)。`autoResolve` 为 true(默认)时 Server 拿到 `req.body`(File/Blob),为 false 时拿到 `req.stream` / `req.body`(`IframeFileReadableStream`)。
|
|
631
|
+
|
|
602
632
|
### 流式传输(Stream)
|
|
603
633
|
|
|
604
634
|
对于大文件或需要分块传输的场景,可以使用流式传输:
|
|
@@ -608,7 +638,7 @@ import {
|
|
|
608
638
|
IframeWritableStream,
|
|
609
639
|
IframeFileWritableStream,
|
|
610
640
|
isIframeReadableStream,
|
|
611
|
-
|
|
641
|
+
isIframeFileReadableStream
|
|
612
642
|
} from 'request-iframe';
|
|
613
643
|
|
|
614
644
|
// Server 端:使用迭代器发送数据流
|
|
@@ -692,7 +722,7 @@ if (isIframeReadableStream(response.stream)) {
|
|
|
692
722
|
// Client 端:接收文件流
|
|
693
723
|
const fileResponse = await client.send('/api/fileStream', {});
|
|
694
724
|
|
|
695
|
-
if (
|
|
725
|
+
if (isIframeFileReadableStream(fileResponse.stream)) {
|
|
696
726
|
// 读取为 Blob
|
|
697
727
|
const blob = await fileResponse.stream.readAsBlob();
|
|
698
728
|
|
|
@@ -714,9 +744,9 @@ if (isIframeFileStream(fileResponse.stream)) {
|
|
|
714
744
|
| 类型 | 说明 |
|
|
715
745
|
|------|------|
|
|
716
746
|
| `IframeWritableStream` | 服务端可写流,用于发送普通数据 |
|
|
717
|
-
| `IframeFileWritableStream` |
|
|
747
|
+
| `IframeFileWritableStream` | 服务端文件可写流(文件流) |
|
|
718
748
|
| `IframeReadableStream` | 客户端可读流,用于接收普通数据 |
|
|
719
|
-
| `IframeFileReadableStream` |
|
|
749
|
+
| `IframeFileReadableStream` | 客户端文件可读流(文件流) |
|
|
720
750
|
|
|
721
751
|
**流选项:**
|
|
722
752
|
|
|
@@ -852,14 +882,16 @@ await client.send('/api/longTask', {}, {
|
|
|
852
882
|
|
|
853
883
|
#### client.send(path, body?, options?)
|
|
854
884
|
|
|
855
|
-
|
|
885
|
+
发送请求。会根据 body 类型自动分发到 `sendFile()` 或 `sendStream()`:
|
|
886
|
+
- `File/Blob` → `sendFile()`
|
|
887
|
+
- `IframeWritableStream` → `sendStream()`
|
|
856
888
|
|
|
857
889
|
**参数:**
|
|
858
890
|
|
|
859
891
|
| 参数 | 类型 | 说明 |
|
|
860
892
|
|------|------|------|
|
|
861
893
|
| `path` | `string` | 请求路径 |
|
|
862
|
-
| `body` | `
|
|
894
|
+
| `body` | `any` | 请求数据(可选)。可以是普通对象、File、Blob、或 IframeWritableStream;会自动分发:File/Blob → `sendFile()`,IframeWritableStream → `sendStream()` |
|
|
863
895
|
| `options.ackTimeout` | `number` | ACK 确认超时(ms),默认 1000 |
|
|
864
896
|
| `options.timeout` | `number` | 请求超时(ms),默认 5000 |
|
|
865
897
|
| `options.asyncTimeout` | `number` | 异步超时(ms),默认 120000 |
|
|
@@ -880,6 +912,69 @@ interface Response<T = any> {
|
|
|
880
912
|
}
|
|
881
913
|
```
|
|
882
914
|
|
|
915
|
+
**示例:**
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
// 发送普通对象(自动 Content-Type: application/json)
|
|
919
|
+
await client.send('/api/data', { name: 'test' });
|
|
920
|
+
|
|
921
|
+
// 发送字符串(自动 Content-Type: text/plain)
|
|
922
|
+
await client.send('/api/text', 'Hello');
|
|
923
|
+
|
|
924
|
+
// 发送 File/Blob(自动分发到 sendFile)
|
|
925
|
+
const file = new File(['content'], 'test.txt');
|
|
926
|
+
await client.send('/api/upload', file);
|
|
927
|
+
|
|
928
|
+
// 发送流(自动分发到 sendStream)
|
|
929
|
+
const stream = new IframeWritableStream({ iterator: async function* () { yield 'data'; } });
|
|
930
|
+
await client.send('/api/uploadStream', stream);
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
#### client.sendFile(path, content, options?)
|
|
934
|
+
|
|
935
|
+
发送文件作为请求体(通过流传输;当 `autoResolve` 为 true 时,Server 在 `req.body` 中拿到 File/Blob)。
|
|
936
|
+
|
|
937
|
+
**参数:**
|
|
938
|
+
|
|
939
|
+
| 参数 | 类型 | 说明 |
|
|
940
|
+
|------|------|------|
|
|
941
|
+
| `path` | `string` | 请求路径 |
|
|
942
|
+
| `content` | `string \| Blob \| File` | 文件内容 |
|
|
943
|
+
| `options.mimeType` | `string` | MIME 类型(可选,优先使用 content.type) |
|
|
944
|
+
| `options.fileName` | `string` | 文件名(可选) |
|
|
945
|
+
| `options.autoResolve` | `boolean` | 为 true(默认)时 Server 在 `req.body` 中拿到 File/Blob;为 false 时 Server 在 `req.stream` / `req.body` 中拿到 `IframeFileReadableStream` |
|
|
946
|
+
| `options.ackTimeout` | `number` | ACK 确认超时(ms),默认 1000 |
|
|
947
|
+
| `options.timeout` | `number` | 请求超时(ms),默认 5000 |
|
|
948
|
+
| `options.asyncTimeout` | `number` | 异步超时(ms),默认 120000 |
|
|
949
|
+
| `options.headers` | `object` | 请求 headers(可选) |
|
|
950
|
+
| `options.cookies` | `object` | 请求 cookies(可选) |
|
|
951
|
+
| `options.requestId` | `string` | 自定义请求 ID(可选) |
|
|
952
|
+
|
|
953
|
+
**返回值:** `Promise<Response>`
|
|
954
|
+
|
|
955
|
+
**说明:** 文件通过流发送。`autoResolve` 为 true(默认)时 Server 收到 `req.body`(File/Blob);为 false 时 Server 收到 `req.stream` / `req.body`(`IframeFileReadableStream`)。
|
|
956
|
+
|
|
957
|
+
#### client.sendStream(path, stream, options?)
|
|
958
|
+
|
|
959
|
+
发送流作为请求体(Server 端收到可读流)。
|
|
960
|
+
|
|
961
|
+
**参数:**
|
|
962
|
+
|
|
963
|
+
| 参数 | 类型 | 说明 |
|
|
964
|
+
|------|------|------|
|
|
965
|
+
| `path` | `string` | 请求路径 |
|
|
966
|
+
| `stream` | `IframeWritableStream` | 要发送的可写流 |
|
|
967
|
+
| `options.ackTimeout` | `number` | ACK 确认超时(ms),默认 1000 |
|
|
968
|
+
| `options.timeout` | `number` | 请求超时(ms),默认 5000 |
|
|
969
|
+
| `options.asyncTimeout` | `number` | 异步超时(ms),默认 120000 |
|
|
970
|
+
| `options.headers` | `object` | 请求 headers(可选) |
|
|
971
|
+
| `options.cookies` | `object` | 请求 cookies(可选) |
|
|
972
|
+
| `options.requestId` | `string` | 自定义请求 ID(可选) |
|
|
973
|
+
|
|
974
|
+
**返回值:** `Promise<Response>`
|
|
975
|
+
|
|
976
|
+
**说明:** Server 端的流在 `req.stream`(`IIframeReadableStream`)中,可用 `for await (const chunk of req.stream)` 迭代读取。
|
|
977
|
+
|
|
883
978
|
#### client.isConnect()
|
|
884
979
|
|
|
885
980
|
检测 Server 是否可达。
|
|
@@ -952,6 +1047,39 @@ client.interceptors.response.use(onFulfilled, onRejected?);
|
|
|
952
1047
|
type ServerHandler = (req: ServerRequest, res: ServerResponse) => any | Promise<any>;
|
|
953
1048
|
```
|
|
954
1049
|
|
|
1050
|
+
**ServerRequest 接口:**
|
|
1051
|
+
|
|
1052
|
+
```typescript
|
|
1053
|
+
interface ServerRequest {
|
|
1054
|
+
body: any; // 请求 body(普通数据;或 autoResolve=true 时的 File/Blob)
|
|
1055
|
+
stream?: IIframeReadableStream; // 请求流(sendStream;或 sendFile 且 autoResolve=false)
|
|
1056
|
+
headers: Record<string, string>; // 请求 headers
|
|
1057
|
+
cookies: Record<string, string>; // 请求 cookies
|
|
1058
|
+
path: string; // 请求路径(实际请求路径)
|
|
1059
|
+
params: Record<string, string>; // 路由参数(由 server.on 注册的路径模式解析得出,如 /api/users/:id)
|
|
1060
|
+
requestId: string; // 请求 ID
|
|
1061
|
+
origin: string; // 来源 origin
|
|
1062
|
+
source: Window; // 来源 window
|
|
1063
|
+
res: ServerResponse; // 关联的 Response 对象
|
|
1064
|
+
}
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
**说明:**
|
|
1068
|
+
- Client 通过 `sendFile()`(或 `send(path, file)`)发送文件时:文件通过流传输;`autoResolve` 为 true(默认)时 Server 在 `req.body` 中拿到 File/Blob;为 false 时在 `req.stream` / `req.body` 中拿到 `IframeFileReadableStream`。
|
|
1069
|
+
- Client 通过 `sendStream()` 发送流时:Server 在 `req.stream` 中拿到 `IIframeReadableStream`,可用 `for await` 迭代读取。
|
|
1070
|
+
- **路径参数(类似 Express)**:支持 `/api/users/:id` 形式的路由参数,解析结果在 `req.params` 中。
|
|
1071
|
+
|
|
1072
|
+
```typescript
|
|
1073
|
+
server.on('/api/users/:id', (req, res) => {
|
|
1074
|
+
res.send({ userId: req.params.id });
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
server.on('/api/users/:userId/posts/:postId', (req, res) => {
|
|
1078
|
+
const { userId, postId } = req.params;
|
|
1079
|
+
res.send({ userId, postId });
|
|
1080
|
+
});
|
|
1081
|
+
```
|
|
1082
|
+
|
|
955
1083
|
#### server.off(path)
|
|
956
1084
|
|
|
957
1085
|
移除路由处理器。
|
|
@@ -1245,10 +1373,12 @@ const IframeComponent = () => {
|
|
|
1245
1373
|
|
|
1246
1374
|
```typescript
|
|
1247
1375
|
interface ServerRequest {
|
|
1248
|
-
body: any; // 请求 body
|
|
1376
|
+
body: any; // 请求 body(普通数据;或 autoResolve=true 时的 File/Blob)
|
|
1377
|
+
stream?: IIframeReadableStream; // 请求流(sendStream;或 sendFile 且 autoResolve=false)
|
|
1249
1378
|
headers: Record<string, string>; // 请求 headers
|
|
1250
1379
|
cookies: Record<string, string>; // 请求 cookies
|
|
1251
|
-
path: string; //
|
|
1380
|
+
path: string; // 请求路径(实际请求路径)
|
|
1381
|
+
params: Record<string, string>; // 路由参数(由 server.on 注册的路径模式解析得出,如 /api/users/:id)
|
|
1252
1382
|
requestId: string; // 请求 ID
|
|
1253
1383
|
origin: string; // 来源 origin
|
|
1254
1384
|
source: Window; // 来源 window
|
|
@@ -1256,6 +1386,22 @@ interface ServerRequest {
|
|
|
1256
1386
|
}
|
|
1257
1387
|
```
|
|
1258
1388
|
|
|
1389
|
+
**路径参数(类似 Express)**:
|
|
1390
|
+
|
|
1391
|
+
支持使用 `:param` 形式声明路由参数,解析结果在 `req.params` 中。
|
|
1392
|
+
|
|
1393
|
+
```typescript
|
|
1394
|
+
server.on('/api/users/:id', (req, res) => {
|
|
1395
|
+
// 请求 /api/users/123 时:req.params.id === '123'
|
|
1396
|
+
res.send({ userId: req.params.id });
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
server.on('/api/users/:userId/posts/:postId', (req, res) => {
|
|
1400
|
+
const { userId, postId } = req.params;
|
|
1401
|
+
res.send({ userId, postId });
|
|
1402
|
+
});
|
|
1403
|
+
```
|
|
1404
|
+
|
|
1259
1405
|
### ServerResponse 对象
|
|
1260
1406
|
|
|
1261
1407
|
```typescript
|