SvelteKit 的 Node 服务器

SvelteKitBuild and deploy

使用 adapter-node 可以生成独立的 Node 服务器。 adapter-node

一种快速开始的方法是使用 SvelteKit 官方 Railway 模板部署项目。 official Railway template

用法 相关文档

运行 npx sv add sveltekit-adapter=”adapter:node”,或者执行 npm i -D @sveltejs/adapter-node 安装,然后在 vite.config.js 中添加适配器: npx sv add sveltekit-adapter=”adapter:node”

vite.config
import adapter from '@sveltejs/adapter-node';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [
		sveltekit({
			adapter: adapter()
		})
	]
});

部署 相关文档

首先运行 npm run build 构建应用。生产服务器会生成在适配器选项指定的输出目录中,默认目录为 build。

运行应用需要输出目录、项目的 package.json,以及 node_modules 中的生产依赖。可以复制 package.json 和 package-lock.json,再运行 npm ci –omit dev 安装生产依赖;应用没有依赖时可跳过这一步。随后用以下命令启动:

node build

开发依赖会通过 Rolldown 打包进应用。若要控制某个包是打包还是保持外部依赖,分别将它放入 package.json 的 devDependencies 或 dependencies。 Rolldown

客户端资源和预渲染产物依据构建期间记录的文件列表提供。

压缩响应 相关文档

通常应该压缩服务器响应。如果已将服务器部署在用于 SSL 或负载均衡的反向代理之后,一般在代理层处理压缩性能更好,因为 Node.js 是单线程的。

如果构建自定义服务器并希望添加压缩中间件,推荐使用 @polka/compression。SvelteKit 会流式输出响应,而更常见的 compression 包不支持流式处理,使用时可能出错。 custom server @polka/compression

环境变量 相关文档

在 dev 和 preview 模式下,SvelteKit 会读取 .env 文件中的环境变量,也可能读取 .env.local 或 .env.[mode],具体规则由 Vite 决定。 as determined by Vite

生产环境不会自动加载 .env 文件。需要加载时,运行构建后的应用应使用 –env-file 参数: –env-file

node --env-file=.env build

PORT、HOST 与 SOCKET_PATH 相关文档

默认服务器监听 0.0.0.0 的 3000 端口。可通过 PORT 和 HOST 环境变量自定义:

HOST=127.0.0.1 PORT=4000 node build

也可以通过 SOCKET_PATH 环境变量设置套接字路径,让服务器从该套接字接受连接;此时会忽略 HOST 和 PORT。

SOCKET_PATH=/tmp/socket node build

PROTOCOL_HEADER、HOST_HEADER 与 PORT_HEADER 相关文档

HTTP 本身无法让 SvelteKit 可靠地知道当前请求的 URL。默认情况下,SvelteKit 根据请求的 host 头推导 origin;未设置 PROTOCOL_HEADER 时,协议使用 https。

如果应用的 origin 无法在请求时确定,例如反向代理不传递 host 头,或希望 CSRF 检查采用与请求主机不同的规范 origin,可以在 vite.config.js 中设置 paths.origin: paths.origin

vite.config
import adapter from '@sveltejs/adapter-node';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [
		sveltekit({
			adapter: adapter(),
			paths: {
				origin: process.env.ORIGIN
			}
		})
	]
});

未设置 paths.origin(默认情况)时,adapter-node 根据请求推导 origin,使用 host 头,以及已设置的 PROTOCOL_HEADER / PORT_HEADER,并据此设置 request.url。设置了 paths.origin 时,该值会作为表单提交和远程函数调用的 CSRF 检查所信任的自身 origin,也会作为预渲染时 url.origin 的值。

另一种方式是指定告知 SvelteKit 请求协议和主机的请求头,由这些值构造 origin URL:

PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build

使用反向代理,例如负载均衡器或 CDN 时,x-forwarded-proto 与 x-forwarded-host 是转发原始协议和主机的事实标准请求头。只有服务器位于可信反向代理之后时才能设置这些变量,否则客户端可以伪造这些请求头。 x-forwarded-proto x-forwarded-host

如果代理使用非标准端口,并支持 x-forwarded-port,还可以设置 PORT_HEADER=x-forwarded-port。

如果 adapter-node 无法正确确定部署 URL,使用表单操作时可能出现以下错误: form actions

Cross-site POST form submissions are forbidden(禁止跨站 POST 表单提交)

ADDRESS_HEADER 与 XFF_DEPTH 相关文档

传给 hooks 和端点的 RequestEvent 对象包含 event.getClientAddress(),用于返回客户端 IP 地址。默认取连接的 remoteAddress。如果服务器前面有一个或多个代理,例如负载均衡器,这个值会是最内层代理的 IP,而不是客户端 IP。因此需要指定 ADDRESS_HEADER,从请求头读取地址: RequestEvent

ADDRESS_HEADER=True-Client-IP node build

请求头很容易伪造。与 PROTOCOL_HEADER 和 HOST_HEADER 一样,设置这些变量前必须明确其信任边界。 know what you’re doing

ADDRESS_HEADER 为 X-Forwarded-For 时,请求头包含用逗号分隔的 IP 列表。XFF_DEPTH 应设置为服务器前方可信代理的数量。例如存在三个可信代理时,第3个代理会转发原始连接和前两个代理的地址:

<client address>, <proxy 1 address>, <proxy 2 address>

有些指南建议读取最左侧地址,但这会让你受到伪造攻击: vulnerable to spoofing

<spoofed address>, <client address>, <proxy 1 address>, <proxy 2 address>

应从右侧读取,并考虑可信代理数量。本例使用 XFF_DEPTH=3。

如果确实需要读取最左侧地址且不关心伪造问题,例如地理位置服务更看重 IP 是否真实而不是是否可信,可以在应用中直接检查 x-forwarded-for 头。

BODY_SIZE_LIMIT 相关文档

允许接收的请求体最大字节数,包括流式接收期间。也可以使用 K、M、G 单位后缀,分别表示千字节、兆字节和吉字节,例如 512K 或 1M。默认值为 512 KB。设为 Infinity 可以禁用此选项,旧版适配器使用 0;需要更复杂的检查时,可在 handle 中自行实现。 handle

SHUTDOWN_TIMEOUT 相关文档

收到 SIGTERM 或 SIGINT 后,在强制关闭剩余连接之前等待的秒数。默认为 30。内部会调用 closeAllConnections。更多信息见优雅关闭。 closeAllConnections Graceful shutdown

IDLE_TIMEOUT 相关文档

使用 systemd 套接字激活时,IDLE_TIMEOUT 指定多少秒未收到请求后自动让应用休眠。未设置时,应用持续运行。详见套接字激活。 Socket activation

KEEP_ALIVE_TIMEOUT 与 HEADERS_TIMEOUT 相关文档

分别为 keepAliveTimeout 和 headersTimeout 设置秒数。 keepAliveTimeout headersTimeout

选项 相关文档

适配器可以通过以下选项配置:

vite.config
import adapter from '@sveltejs/adapter-node';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [
		sveltekit({
			adapter: adapter({
				// default options are shown
				out: 'build',
				precompress: true,
				envPrefix: ''
			})
		})
	]
});

out

服务器构建输出目录,默认为 build。构建完成后,执行 node build 即可在本地启动服务器。

precompress

构建时为客户端资源和预渲染资源生成 .br 与 .gz 版本。服务器逐请求协商 Accept-Encoding,优先使用 brotli,其次是 gzip;每种版本有独立 ETag。默认值为 true。

envPrefix

如果要修改部署配置环境变量的名称,例如避免与无法控制的环境变量冲突,可以指定前缀:

envPrefix: 'MY_CUSTOM_';
MY_CUSTOM_HOST=127.0.0.1 \
MY_CUSTOM_PORT=4000 \
node build

优雅关闭 相关文档

默认情况下,adapter-node 收到 SIGTERM 或 SIGINT 后会优雅关闭 HTTP 服务器,步骤如下:

  1. 拒绝新请求(server.close)。 server.close
  2. 等待已经发起但尚未收到响应的请求完成,并在连接空闲后关闭连接(server.closeIdleConnections)。 server.closeIdleConnections
  3. 最后,在 SHUTDOWN_TIMEOUT 秒后关闭仍然活动的连接(server.closeAllConnections)。 SHUTDOWN_TIMEOUT server.closeAllConnections

需要自定义此行为时,可以使用自定义服务器。 custom server

可以监听 sveltekit:shutdown 事件,它在 HTTP 服务器关闭所有连接后发出。与 Node 的 exit 事件不同,sveltekit:shutdown 支持异步操作;所有连接关闭后,即便仍有数据库连接等未完成工作,也一定会发出该事件。

process.on('sveltekit:shutdown', async (reason) => {
	await jobs.stop();
	await db.close();
});

reason 参数可能是以下值:

  • SIGINT:由 SIGINT 信号触发关闭。
  • SIGTERM:由 SIGTERM 信号触发关闭。
  • IDLE:由 IDLE_TIMEOUT 触发关闭。 IDLE_TIMEOUT

套接字激活 相关文档

如今大多数 Linux 系统使用 systemd 进程管理器启动系统、运行并管理服务。可以配置服务器预先分配套接字,再按需启动和扩展应用,这称为套接字激活。操作系统向应用传入 LISTEN_PID 和 LISTEN_FDS 两个环境变量,适配器随后监听文件描述符3;它对应需要创建的 systemd socket 单元。 socket activation

套接字激活仍可配合 envPrefix 使用。不过 LISTEN_PID 和 LISTEN_FDS 始终按无前缀名称读取。 envPrefix

按以下步骤使用套接字激活。

  1. 将应用作为 systemd 服务运行,既可直接运行在宿主机,也可运行在容器中,例如 Docker 或 systemd portable service。如果同时设置 IDLE_TIMEOUT,应用会在相应秒数内没有请求时优雅关闭;新请求到来后,systemd 会自动重新启动应用。 systemd service IDLE_TIMEOUT
/etc/systemd/system/myapp
[Service]
Environment=NODE_ENV=production IDLE_TIMEOUT=60
ExecStart=/usr/bin/node /usr/bin/myapp/build
  1. 创建配套的 socket 单元。适配器只接受一个套接字。 socket unit
/etc/systemd/system/myapp
[Socket]
ListenStream=3000

[Install]
WantedBy=sockets.target
  1. 运行 sudo systemctl daemon-reload,使 systemd 识别这两个单元。再执行 sudo systemctl enable –now myapp.socket,启用开机启动并立即启动套接字。第一次请求 localhost:3000 时,应用会自动启动。

自定义服务器 相关文档

build 目录包含 index.js 和 handler.js 两个入口。运行 index.js,例如默认输出目录下的 node build,会在配置的端口启动服务器。

另一种方式是导入 handler.js。它导出的处理器适用于 Express、Connect、Polka,甚至内置的 http.createServer,因此可以自行搭建服务器: Express Connect Polka http.createServer

my-server
import { handler } from './build/handler.js';
import express from 'express';

const app = express();

// add a route that lives separately from the SvelteKit app
app.get('/healthcheck', (req, res) => {
	res.end('ok');
});

// let SvelteKit handle everything else, including serving prerendered pages and static assets
app.use(handler);

app.listen(3000, () => {
	console.log('listening on port 3000');
});

在自定义服务器中使用 handler.js 时,只有处理器本身读取的环境变量会生效:PROTOCOL_HEADER、HOST_HEADER、PORT_HEADER、ADDRESS_HEADER、XFF_DEPTH 和 BODY_SIZE_LIMIT。

服务器生命周期变量 PORT、HOST、SOCKET_PATH、SHUTDOWN_TIMEOUT、IDLE_TIMEOUT、KEEP_ALIVE_TIMEOUT、HEADERS_TIMEOUT、LISTEN_PID、LISTEN_FDS 仅由默认 node build 服务器处理。如果自定义服务器需要相同行为,必须自行实现。例如上面的代码固定监听3000端口,不受 PORT 影响。

在 GitHub 编辑本页;llms.txt Edit this page on GitHub llms.txt

来源与版权

作者/维护者:Svelte 文档团队。原文:https://svelte.dev/docs/kit/adapter-node。原作者与项目贡献者保留版权,中文版本依据已取得的转载授权制作。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容