使用 Astro 进行服务器端渲染

作者
Matthew Phillips

今天,我们很高兴地宣布 Astro 对服务器端渲染 (SSR) 的实验性支持。通过 Astro 中的 SSR,我们解锁了以前不可能实现的全新用例(例如电子商务)和规模。我们的 SSR 实现将 Astro 独特的服务器优先方法与用户认证、登录流程、数据库访问、数据获取等动态功能结合起来。

如果您已准备好开始,请前往文档查阅并开始使用。

动机

我们听到您的声音了!我们最常收到的问题之一是:“Astro 能否进行 SSR?”

当我们着手构建 Astro 时,我们决定专注于预构建的静态站点架构,通常称为“Jamstack”(也称为静态站点生成或 SSG)。这种方法使我们能够快速迭代和推出新功能,但也伴随着一些重要的限制

  • 大型站点无法预渲染为静态 HTML,否则会导致更长的构建时间或更慢的客户端动态内容渲染。
  • 动态站点无法预渲染为静态 HTML,否则在数据更改时,您将被迫重建和重新部署部分站点。
  • 交互式站点无法预渲染为静态 HTML,否则需要将所有用户个性化数据移动到客户端。当您处理静态预构建的 HTML 时,用户名、头像和权限都会变得更加复杂。

电子商务尤其受到上述三个问题的影响。在一个加载性能每一毫秒都至关重要的行业中,如何在没有限制的情况下获得静态 HTML 的出色性能?

从第一天起,我们就知道 Astro 的岛屿架构方法在解决这个问题上具有独特的优势。岛屿允许页面快速加载并延迟变得可交互;用户可以更快地看到页面最重要的部分并与之互动。

隆重推出:服务器端渲染 (SSR)

服务器端渲染是一个众所周知的解决方案,用于扩展大型网站,其历史可以追溯到互联网的早期。SSR 并非万灵药,但如果做得好,对于某些用例来说,SSR 是一个宝贵的工具。

以用户认证为例。使用静态站点生成时,您有几种不同的方法:

  1. 检查 localStorage 中是否存在 cookie 或 JWT,如果用户没有则重定向到登录页面。如果使用 cookie,这将阻止使用 HttpOnly,使您容易受到恶意 JavaScript 攻击。

    <script>
    if (!parseCookie(document.cookie).auth) {
    window.location = "/login"
    }
    </script>

    此外,如果令牌无效,您该怎么办?在这种情况下,您仍然需要检查并做出响应。

  2. 调用一个 API 来检查用户是否已登录,例如 /api/auth。走这条路意味着在等待响应时,您需要在每个岛屿中显示加载指示器。

    function App() {
    const auth = useAuth()
    if (auth.loading) return <AnnoyingLoadingSpinner />
    if (!auth.loggedIn) return <LoginPage />
    return <UserProfile user={auth.user} />
    }

无论您采用哪种方法,客户端认证始终意味着:

  • 如果禁用 JavaScript,则无法运行。
  • 您的服务器只能响应 200 OK 状态码。
  • 这简直太慢了。用户必须等待完整的 HTML 响应(包括 JS、CSS 等),即使他们随后立即重定向。这会在用户到达正确页面之前创建多个页面请求。

Astro SSR:旨在简化

Next.js、Nuxt、Gatsby、SvelteKit 以及所有现代 JavaScript 元框架都对 SSR 有所了解。那么 Astro SSR 有何特别之处呢?

与我们之前处理 SSR 的当前专注于 JavaScript 的元框架相比,Astro 具有一个关键优势:Astro 从设计之初就旨在运行在服务器上。

使用 Astro,您可以自由地按照自己的想法编写服务器代码,摆脱其他“通用”SPA 优先框架带来的不必要抽象。虽然 SPA 优先的思维可能非常适合超有状态的 Web 应用程序(例如仪表板、应用程序、门户),但对于大多数以内容为中心的网站来说,这是一笔不划算的开销。

以下是 Astro SSR 中用户认证的工作方式,只需 5 行 JavaScript 代码:

src/pages/index.astro
---
// In an Astro component (*.astro), you write server code directly
// in the component front matter (this space between the two --- fences).
// 1. Import any dependencies (Full support for JavaScript/TypeScript)
import { getUser } from "../api/index.js"
// 2. Check that the user token exists and is not malicious.
const user = await getUser(Astro.request)
// 3. If no user was found, return a redirect. This instantly
// completes the response with the correct status code & headers.
if (!user) {
return Astro.redirect("/login")
}
// 4. If the user is logged in, you can now use the `user` object
// right in your page template to show an avatar, name, etc.
---
<html>
...
<h1>Hello {user.name} 👋</h1>
<img src={user.avatar} alt={user.name} />
...
</html>

Astro 前置配置就像一个单一的函数调用,它接收一个请求并返回一个渲染好的模板。由于它是一个函数调用,您可以处理请求、获取要馈送到模板的数据,并在需要时提前退出(例如通过重定向)。

API 路由

Astro 的 HTML 优先 Web 开发方法本身就能让您走得很远,但 Astro 也支持使用您喜欢的框架(如 React)构建交互式 UI。当您为客户端构建时,通常需要端点来在用户和服务器之间读写数据。内置的 API 路由可以满足这一需求。

在 Astro 中,API 路由是 src/pages/ 文件夹中的 .js.ts 文件,它接收请求并返回响应。API 路由旨在实现最大灵活性:

  • 构建一个用于无 JS 表单提交的表单提交处理器。
  • 构建一个用于用户文件提交的上传处理器。
  • 构建一个基于 JSON 的 REST API,供客户端与服务器通信。
  • 构建一个动态资产路由,以返回任何文件类型,包括图像和视频。

API 路由通过导出一个实现 HTTP 方法的函数来工作。以下是一个保存用户资料的 API 路由示例:

src/pages/api/profile.js
export async function post(params, request) {
const profile = await request.json()
await saveProfile(profile)
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: {
"Content-Type": "application/json",
},
})
}

适配器:随处部署 Astro

现代网络主机对开发者体验设定了高标准。开发者期望框架能与他们偏好的提供商集成,无需过多配置或设置。

当我们构建 Astro SSR 时,我们评估了其他框架解决这个问题的方式。最终,我们决定追随 SvelteKitRemix 的脚步,采纳**可插拔主机适配器**的概念。适配器是简单的、可插拔的集成,可以自动为您喜欢的托管服务配置构建。

适配器模型不仅易于开发者设置,还允许我们支持尽可能多的不同类型的主机,包括:

  • CloudflareDeno Deploy 一起完全在边缘运行。
  • 在像 NetlifyVercel 这样的现代开发平台上运行。
  • AWSAzureGoogle Cloud 上的裸机无服务器函数中运行。
  • 在您可以自行部署的 JavaScript 服务器运行时(如 Node.jsDeno)上运行。

Astro 中的 SSR 支持仍处于实验阶段。在接下来的两个月里,我们很高兴能与所有主要的托管服务提供商合作,为我们的用户关心的每个平台推出更多适配器和合作关系。如果您是托管服务提供商,并有兴趣为 Astro 构建自己的适配器,请通过 Discord 或电子邮件联系我们:partner@astro.build

为庆祝这一发布,我们有幸与我们的首发合作伙伴(和官方托管赞助商)Netlify 合作,为 Netlify 平台推出了一款官方的、发布即用的适配器。Netlify 适配器只需一行代码即可将您的 Astro SSR 构建配置为在 Netlify Functions 上运行

import { defineConfig } from "astro/config"
import netlify from "@astrojs/netlify/functions"
export default defineConfig({
adapter: netlify(),
})

要部署,请运行您的 astro build 命令,然后部署到 Netlify

后续步骤

服务器端渲染目前作为实验性 API 在 Astro 1.0 Beta 版本中提供。此版本专注于提供低级原语和构建基础。

了解更多

  • 查阅文档以了解 SSR API。
  • 访问我们的Discord 频道获取支持并帮助稳定 API。
  • Twitter上关注我们,本周晚些时候我们将发布更多关于 SSR 的指南。