Skip to main content
Version: 11.x

HTTP 批量流链接

httpBatchStreamLink终止链接,它将一组单独的 tRPC 操作批处理为单个 HTTP 请求,该请求发送到单个 tRPC 过程(相当于 httpBatchLink),但不等待批处理的所有响应准备就绪,并将响应流式传输 一旦有任何数据可用。

¥httpBatchStreamLink is a terminating link that batches an array of individual tRPC operations into a single HTTP request that's sent to a single tRPC procedure (equivalent to httpBatchLink), but doesn't wait for all the responses of the batch to be ready and streams the responses as soon as any data is available.

选项

¥Options

选项与 httpBatchLink options 相同。

¥Options are identical to httpBatchLink options.

用法

¥Usage

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

¥All usage and options are identical to httpBatchLink.

注意

如果你需要能够在程序中更改/设置响应标头(包括 cookie),请确保使用 httpBatchLink!这是因为 httpBatchStreamLink 不支持在流开始后设置标头。阅读更多

¥If you require the ability to change/set response headers (which includes cookies) from within your procedures, make sure to use httpBatchLink instead! This is due to the fact that httpBatchStreamLink does not support setting headers once the stream has begun. Read more.

你可以将 httpBatchStreamLink 导入并添加到 links 数组中,如下所示:

¥You can import and add the httpBatchStreamLink to the links array as such:

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.txt 文件中设置所有程序来使用批处理。下面的代码将生成一个 HTTP 请求,并在服务器上生成一个数据库查询:

¥After that, you can make use of batching by setting all your procedures in a Promise.all. The code below will produce exactly one HTTP request and on the server exactly one database query:

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),
]);

流式模式

¥Streaming mode

当将请求一起批处理时,常规 httpBatchLink 的行为是等待所有请求完成后再发送响应。如果你想在响应准备好后立即发送,可以使用 httpBatchStreamLink。这对于长时间运行的请求很有用。

¥When batching requests together, the behavior of a regular httpBatchLink is to wait for all requests to finish before sending the response. If you want to send responses as soon as they are ready, you can use httpBatchStreamLink instead. This is useful for long-running requests.

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',
}),
],
});

与常规 httpBatchLink 相比,httpBatchStreamLink 将:

¥Compared to a regular httpBatchLink, a httpBatchStreamLink will:

  • 导致请求使用 trpc-accept: application/jsonl 标头发送

    ¥Cause the requests to be sent with a trpc-accept: application/jsonl header

  • 使响应通过 transfer-encoding: chunkedcontent-type: application/jsonl 发送

    ¥Cause the response to be sent with a transfer-encoding: chunked and content-type: application/jsonl

  • 从传递给 responseMeta 的参数对象中删除 data 键(因为对于流式响应,标头是在数据可用之前发送的)

    ¥Remove the data key from the argument object passed to responseMeta (because with a streamed response, the headers are sent before the data is available)

异步生成器和延迟promise

¥Async generators and deferred promises

你可以在 tRPC.io 的主页上尝试此集成:[https://trpc.nodejs.cn/?try=minimal#try-it-out](/?try=minimal#try-it-out)

¥You can try this out on the homepage of tRPC.io: https://trpc.nodejs.cn/?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
}

兼容性(客户端)

¥Compatibility (client-side)

浏览器

¥Browsers

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

¥Browser support should be identical to fetch support.

Node.js / Deno

对于浏览器之外的运行时,fetch 实现应该支持流式传输,这意味着 await fetch(...) 获得的响应应该具有 ReadableStream<Uint8Array> | NodeJS.ReadableStream 类型的 body 属性,这意味着:

¥For runtimes other than the browser ones, the fetch implementation should support streaming, meaning that the response obtained by await fetch(...) should have a body property of type ReadableStream<Uint8Array> | NodeJS.ReadableStream, meaning that:

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

    ¥either response.body.getReader is a function that returns a ReadableStreamDefaultReader<Uint8Array> object

  • 或者 response.bodyUint8Array Buffer

    ¥or response.body is a Uint8Array Buffer

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

¥This includes support for undici, node-fetch, native Node.js fetch implementation, and WebAPI fetch implementation (browsers).

React Native

接收流依赖于 TextDecoderTextDecoderStream API,而 React Native 中不提供这些 API。需要注意的是,如果你的 TextDecoderStream polyfill 不会自动填充 ReadableStreamWritableStream,则也需要填充它们。如果你仍想启用流式传输,则需要对其进行 polyfill。

¥Receiving the stream relies on the TextDecoder and TextDecoderStream APIs, which is not available in React Native. It's important to note that if your TextDecoderStream polyfill does not automatically polyfill ReadableStream and WritableStream those will also need to be polyfilled. If you still want to enable streaming, you need to polyfill those.

你还需要在 httpBatchStreamLink 配置选项中覆盖默认获取。在下面的示例中,我们将使用 Expo fetch 包进行获取实现。

¥You will also need to overide the default fetch in the httpBatchStreamLink configuration options. In the below example we will be using the Expo fetch package for the fetch implementation.

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

兼容性(服务器端)

¥Compatibility (server-side)

⚠️ 对于 aws lambda,不支持 httpBatchStreamLink(将简单地表现得像常规 httpBatchLink)。如果启用它不会破坏任何东西,但不会产生任何效果。

¥⚠️ for aws lambda, httpBatchStreamLink is not supported (will simply behave like a regular httpBatchLink). It should not break anything if enabled, but will not have any effect.

⚠️ 对于 cloudflare 工作线程,你需要通过功能标志启用 ReadableStream API:streams_enable_constructors

¥⚠️ for cloudflare workers, you need to enable the ReadableStream API through a feature flag: streams_enable_constructors

参考

¥Reference

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

¥You can check out the source code for this link on GitHub.

配置 ping 选项以保持连接活动

¥Configure a ping option to keep the connection alive

设置根配置时,你可以传入 jsonl 选项来配置 ping 选项以保持连接处于活动状态。

¥When setting up your root config, you can pass in a jsonl option to configure a ping option to keep the connection alive.

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,
},
});