使用 renderToWebStream 实现流式 SSR
比较 renderToWebStream() 与 renderToString()、HTTP 流式传输、改善 TTFB,以及分块刷新
使用 renderToWebStream 实现流式 SSR 是 CoddyKit 上的免费 Vue Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Vue Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Vue Academy 课程共包含 4 节课。
从 renderToString 到流式渲染
经典 SSR 使用 renderToString,它会先在内存中构建完整的 HTML,然后再一次性发送一个字节也不差的完整结果。浏览器会一直等待,直到整个页面准备就绪。
流式 SSR 会随着应用渲染逐块发送 HTML,因此浏览器可以更早开始解析。
renderToWebStream 基础
Vue 的服务器渲染器提供了流式函数。renderToWebStream 返回一个 ReadableStream(网页流 API),而 renderToNodeStream/pipeToNodeWritable 面向 Node 的流接口。
组件树每解析完成一部分,就会刷新对应的分块。
import { renderToWebStream } from 'vue/server-renderer'
import { createSSRApp } from 'vue'
import App from './App.vue'
const app = createSSRApp(App)
const stream = renderToWebStream(app)将流传输到 HTTP 响应
在服务器中,您需要将流传输到响应中。使用 pipeToNodeWritable 可以直接写入 res 可写流,并在分块生成时刷新它们。
import { pipeToNodeWritable } from 'vue/server-renderer'
server.get('*', (req, res) => {
const app = createSSRApp(App)
res.write('<!DOCTYPE html><html><body><div id="app">')
pipeToNodeWritable(app, {}, res)
})在网页/边缘运行时中进行流式传输
在边缘运行时(Workers、Deno、Bun)中,您可以直接返回由网页流构建的 Response。整个过程不涉及 Node 流。
import { renderToWebStream } from 'vue/server-renderer'
export default async function handler(request) {
const app = createSSRApp(App)
const stream = renderToWebStream(app)
return new Response(stream, {
headers: { 'Content-Type': 'text/html' }
})
}分块如何到达浏览器
Vue 渲染节点时,会将序列化后的 HTML 字符串推入流中。HTTP 层会立即刷新这些字节。浏览器的增量 HTML 解析器会在响应完成之前渲染可见内容。
因此,即使页面主体仍在传输,用户也能先看到页头和布局。
TTFB:关键指标
TTFB(首字节时间)衡量的是收到第一个响应字节所需的时间。
使用 renderToString 时,TTFB 包含完整的渲染时间。使用流式传输时,第一个分块几乎会立即离开服务器,从而大幅降低 TTFB 并改善用户感知的速度。
// renderToString: client waits for full HTML
const html = await renderToString(app) // blocks
res.end(fullPage(html))
// streaming: first bytes flush right away
pipeToNodeWritable(app, {}, res) // non-blocking chunks使用布局 HTML 包裹流
通常需要在应用流之前发送文档外壳(<head> 和开始标签),并在应用流之后发送结束标签。先写入前缀,传输应用流,然后在流结束时写入后缀。
res.write('<!DOCTYPE html><head><title>App</title></head>')
res.write('<body><div id="app">')
pipeToNodeWritable(app, ctx, {
write: (chunk) => res.write(chunk),
end: () => res.end('</div></body></html>')
})流式传输过程中的错误处理
字节一旦刷新,您就无法再更改 HTTP 状态码。请通过 onError 选项(或可写流的错误路径)处理渲染错误。对于早期检测到的严重失败,请优先使用非流式渲染,这样仍然可以发送 500 状态码。
pipeToNodeWritable(app, ctx, {
write: (c) => res.write(c),
end: () => res.end(suffix),
destroy: (err) => {
console.error('Stream failed:', err)
res.end() // status already sent
}
})流式传输后的水合
流式传输的 HTML 仍然会在客户端通过 createSSRApp().mount() 完成水合。Vue 会在现有 DOM 上附加监听器,而不是重新创建 DOM。流式传输只影响标记的交付方式,不会改变水合的工作方式。
// client entry
import { createSSRApp } from 'vue'
import App from './App.vue'
createSSRApp(App).mount('#app') // hydrates streamed markup流式传输与异步数据
对于依赖数据的组件,请在流式传输之前或期间解析关键数据。当组件树的各部分彼此独立时,流式传输最能发挥作用:外壳会立即传输,而较慢的部分会在其数据准备好后继续渲染。
// fetch critical data, then stream the rest
const app = createSSRApp(App, { initialData })
const stream = renderToWebStream(app)
return new Response(stream, {
headers: { 'Content-Type': 'text/html' }
})何时选择流式传输
对于内容丰富、重视 TTFB 和用户感知速度,并且可以先发送稳定外壳的页面,请使用流式传输。对于小型页面,或需要完全控制最终状态码和响应头的情况,请继续使用 renderToString。
快速检查
检验您对流式 SSR 的理解。
回顾
您已经学习了流式 SSR:
renderToWebStream返回 ReadableStream;服务器端使用pipeToNodeWritable- 分块会随着组件树渲染而刷新,因此浏览器可以增量解析
- 与阻塞式的
renderToString相比,这会降低 TTFB - 在流周围写入文档外壳;首次刷新后的错误无法更改状态码
- 使用
createSSRApp().mount()进行水合的方式不变
用 AI 导师学习 HTML — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 42
- 课程
- 156
常见问题解答
「使用 renderToWebStream 实现流式 SSR」课时是免费的吗?
是的 — 「使用 renderToWebStream 实现流式 SSR」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Vue Academy 课程的其余内容,请升级到 CoddyKit PRO。 Vue Academy 课程共包含 4 节课。
「使用 renderToWebStream 实现流式 SSR」这节课中我会学到什么?
比较 renderToWebStream() 与 renderToString()、HTTP 流式传输、改善 TTFB,以及分块刷新 你通过在浏览器中直接运行的动手代码来练习 Vue Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Vue Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Vue Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「使用 renderToWebStream 实现流式 SSR」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Vue Academy 课中编写并运行代码吗?
能。每节 Vue Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- Vue Suspense 组件
- 使用 defineAsyncComponent 加载异步组件
- 使用 renderToWebStream 实现流式 SSR
- 延迟 Hydration 策略