跳至主内容
版本:11.x

HTTP 批处理流式链接

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

httpBatchStreamLink 是一个终止链接,它将多个独立的 tRPC 操作批处理成单个 HTTP 请求发送到单个 tRPC 过程(等同于 httpBatchLink),但不会等待批处理中所有响应准备完成,而是在任何数据可用时立即流式传输响应。

选项

配置选项与 httpBatchLink options 完全相同。

用法

所有用法和选项均与 httpBatchLink 完全相同。

备注

如果需要在过程中修改/设置响应头(包括 cookies),请务必改用 httpBatchLink!这是因为 httpBatchStreamLink 不支持在流启动后设置响应头。了解更多

您可以通过以下方式导入并将 httpBatchStreamLink 添加到 links 数组:

client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});

之后,您可以通过将所有过程放入 Promise.all 来利用批处理功能。以下代码将产生仅一次 HTTP 请求,在服务器端执行仅一次数据库查询:

ts
const somePosts = await Promise.all([
trpc.post.byId.query(1),
trpc.post.byId.query(2),
trpc.post.byId.query(3),
]);
ts
const somePosts = await Promise.all([
trpc.post.byId.query(1),
trpc.post.byId.query(2),
trpc.post.byId.query(3),
]);

流式模式

当批量处理请求时,常规 httpBatchLink 的行为是等待所有请求完成后再发送响应。如果您希望在响应就绪时立即发送,可以改用 httpBatchStreamLink。这对于长时间运行的请求非常有用。

client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});

相比常规 httpBatchLinkhttpBatchStreamLink 将:

  • 在请求头中添加 trpc-accept: application/jsonl

  • 在响应头中添加 transfer-encoding: chunkedcontent-type: application/jsonl

  • 从传递给 responseMeta 的参数对象中移除 data 键(因为使用流式响应时,标头在数据可用前就已发送)

异步生成器与延迟 Promise

您可以在 tRPC.io 首页体验此功能:https://trpc.io/?try=minimal#try-it-out

ts
// @filename: server.ts
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
examples: {
iterable: publicProcedure.query(async function* () {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
yield i;
}
}),
},
});
 
export type AppRouter = typeof appRouter;
 
 
// @filename: client.ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from './server';
 
const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
const iterable = await trpc.examples.iterable.query();
const iterable: AsyncIterable<number, never, unknown>
 
for await (const value of iterable) {
console.log('Iterable:', value);
const value: number
}
ts
// @filename: server.ts
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
examples: {
iterable: publicProcedure.query(async function* () {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
yield i;
}
}),
},
});
 
export type AppRouter = typeof appRouter;
 
 
// @filename: client.ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from './server';
 
const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
const iterable = await trpc.examples.iterable.query();
const iterable: AsyncIterable<number, never, unknown>
 
for await (const value of iterable) {
console.log('Iterable:', value);
const value: number
}

兼容性(客户端)

浏览器

浏览器支持应与 fetch 支持范围相同。

Node.js / Deno

对于非浏览器运行时,fetch 实现需支持流式传输,即通过 await fetch(...) 获取的响应应具有类型为 ReadableStream<Uint8Array> | NodeJS.ReadableStreambody 属性,这意味着:

  • response.body.getReader 是返回 ReadableStreamDefaultReader<Uint8Array> 对象的函数

  • response.bodyUint8Array 类型的 Buffer

这包括对 undicinode-fetch、原生 Node.js fetch 实现和 WebAPI fetch 实现(浏览器)的支持。

React Native

接收流依赖于 TextDecoderTextDecoderStream API,而 React Native 不提供这些 API。请注意:如果您的 TextDecoderStream 垫片未自动填充 ReadableStreamWritableStream,则需额外填充这些对象。若仍需启用流式传输,必须自行填充这些 API。

您还需要在 httpBatchStreamLink 的配置选项中覆盖默认的 fetch 实现。在下面的示例中,我们将使用 Expo fetch 包作为 fetch 的实现方案。

typescript
httpBatchStreamLink({
fetch: (url, opts) =>
fetch(url, {
...opts,
reactNative: { textStreaming: true },
}),
...restOfConfig,
});
typescript
httpBatchStreamLink({
fetch: (url, opts) =>
fetch(url, {
...opts,
reactNative: { textStreaming: true },
}),
...restOfConfig,
});

兼容性(服务端)

⚠️ 对于 AWS LambdahttpBatchStreamLink 不受支持(行为等同于常规 httpBatchLink)。启用后不会导致功能异常,但不会产生任何效果。

⚠️ 在 Cloudflare Workers 中,需通过特性标志启用 ReadableStream API:streams_enable_constructors

参考文档

您可以在 GitHub 查看此链接的源代码。

配置 ping 选项保持连接活跃

在设置根配置时,可以传入 jsonl 选项来配置 ping 机制以保持连接活跃。

ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create({
jsonl: {
pingMs: 1000,
},
});
ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create({
jsonl: {
pingMs: 1000,
},
});