节点服务器
要生成独立的 Node 服务器,请使用 adapter-node
。
用法
使用 npm i -D @sveltejs/adapter-node
安装,然后将适配器添加到您的 svelte.config.js
中
import import adapter
adapter from '@sveltejs/adapter-node';
export default {
kit: {
adapter: any;
}
kit: {
adapter: any
adapter: import adapter
adapter()
}
};
部署
首先,使用 npm run build
构建您的应用。这将在适配器选项中指定的输出目录中创建生产服务器,默认为 build
。
您将需要输出目录、项目的 package.json
以及 node_modules
中的生产依赖项来运行应用程序。生产依赖项可以通过复制 package.json
和 package-lock.json
然后运行 npm ci --omit dev
来生成(如果您的应用程序没有任何依赖项,则可以跳过此步骤)。然后,您可以使用以下命令启动您的应用程序
node build
开发依赖项将使用 Rollup 捆绑到您的应用程序中。要控制是否捆绑或外部化给定的包,请分别将其放在 package.json
中的 devDependencies
或 dependencies
中。
压缩响应
您通常希望压缩来自服务器的响应。如果您已经将服务器部署在反向代理后面以进行 SSL 或负载均衡,则通常在该层处理压缩也会带来更好的性能,因为 Node.js 是单线程的。
但是,如果您正在构建 自定义服务器 并确实希望在那里添加压缩中间件,请注意,我们建议使用 @polka/compression
,因为 SvelteKit 流式传输响应,而更流行的 compression
包不支持流式传输,并且在使用时可能会导致错误。
环境变量
在 dev
和 preview
中,SvelteKit 将从您的 .env
文件(或 .env.local
,或 .env.[mode]
,由 Vite 确定。)读取环境变量。
在生产环境中,不会自动加载 .env
文件。要执行此操作,请在您的项目中安装 dotenv
...
npm install dotenv
...并在运行构建后的应用程序之前调用它
node -r dotenv/config build
如果您使用 Node.js v20.6+,则可以使用 --env-file
标志代替
node --env-file=.env build
PORT、HOST 和 SOCKET_PATH
默认情况下,服务器将使用端口 3000 接受来自 0.0.0.0
的连接。这些可以通过 PORT
和 HOST
环境变量自定义
HOST=127.0.0.1 PORT=4000 node build
或者,可以将服务器配置为接受指定套接字路径上的连接。当使用 SOCKET_PATH
环境变量执行此操作时,HOST
和 PORT
环境变量将被忽略。
SOCKET_PATH=/tmp/socket node build
ORIGIN、PROTOCOL_HEADER、HOST_HEADER 和 PORT_HEADER
HTTP 无法为 SvelteKit 提供可靠的方式来了解当前正在请求的 URL。告知 SvelteKit 应用服务位置的最简单方法是设置 ORIGIN
环境变量
ORIGIN=https://my.site node build
# or e.g. for local previewing and testing
ORIGIN=https://127.0.0.1:3000 node build
这样,对 /stuff
路径名的请求将正确解析为 https://my.site/stuff
。或者,您可以指定告诉 SvelteKit 关于请求协议和主机的主机头,SvelteKit 可以从中构造原始 URL
PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build
x-forwarded-proto
和x-forwarded-host
是事实上的标准标头,如果您使用反向代理(考虑负载均衡器和 CDN),则会转发原始协议和主机。您应该仅在您的服务器位于受信任的反向代理后面时才设置这些变量;否则,客户端可能会欺骗这些标头。如果您在非标准端口上托管代理,并且您的反向代理支持
x-forwarded-port
,您还可以设置PORT_HEADER=x-forwarded-port
。
如果 adapter-node
无法正确确定部署的 URL,则在使用 表单操作 时可能会遇到此错误
禁止跨站点 POST 表单提交
ADDRESS_HEADER 和 XFF_DEPTH
传递给钩子和端点的 RequestEvent 对象包含一个 event.getClientAddress()
函数,该函数返回客户端的 IP 地址。默认情况下,这是连接的 remoteAddress
。如果您的服务器位于一个或多个代理(例如负载均衡器)后面,则此值将包含最内层代理的 IP 地址而不是客户端的 IP 地址,因此我们需要指定 ADDRESS_HEADER
来读取地址
ADDRESS_HEADER=True-Client-IP node build
标头很容易被伪造。与
PROTOCOL_HEADER
和HOST_HEADER
一样,您应该在设置这些标头之前 了解自己在做什么。
如果 ADDRESS_HEADER
为 X-Forwarded-For
,则标头值将包含一个用逗号分隔的 IP 地址列表。XFF_DEPTH
环境变量应指定服务器前面有多少个受信任的代理。例如,如果有三个受信任的代理,代理 3 将转发原始连接和前两个代理的地址
<client address>, <proxy 1 address>, <proxy 2 address>
一些指南会告诉您读取最左边的地址,但这会让您 容易受到欺骗
<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
。默认为 512kb。您可以使用 Infinity
(在旧版本的适配器中为 0)的值禁用此选项,并在需要更高级功能的情况下在 handle
中实现自定义检查。
SHUTDOWN_TIMEOUT
在收到 SIGTERM
或 SIGINT
信号后,等待强制关闭任何剩余连接的秒数。默认为 30
。在内部,适配器调用 closeAllConnections
。有关更多详细信息,请参阅 优雅关闭。
IDLE_TIMEOUT
使用 systemd 套接字激活时,IDLE_TIMEOUT
指定在未收到请求时应用程序自动进入睡眠状态的秒数。如果未设置,则应用程序将持续运行。有关更多详细信息,请参阅 套接字激活。
选项
适配器可以使用各种选项进行配置
import import adapter
adapter from '@sveltejs/adapter-node';
export default {
kit: {
adapter: any;
}
kit: {
adapter: any
adapter: import adapter
adapter({
// default options are shown
out: string
out: 'build',
precompress: boolean
precompress: true,
envPrefix: string
envPrefix: ''
})
}
};
out
要将服务器构建到的目录。默认为 build
— 即 node build
将在创建服务器后本地启动服务器。
precompress
启用使用 gzip 和 brotli 对资产和预渲染页面的预压缩。默认为 true
。
envPrefix
如果您需要更改用于配置部署的环境变量的名称(例如,与您无法控制的环境变量冲突),则可以指定前缀
envPrefix: 'MY_CUSTOM_';
MY_CUSTOM_HOST=127.0.0.1 \
MY_CUSTOM_PORT=4000 \
MY_CUSTOM_ORIGIN=https://my.site \
node build
优雅关闭
默认情况下,adapter-node
在收到 SIGTERM
或 SIGINT
信号时会优雅地关闭 HTTP 服务器。它将
- 拒绝新请求 (
server.close
) - 等待已发出但尚未收到响应的请求完成,并在连接空闲时关闭连接 (
server.closeIdleConnections
) - 最后,关闭在
SHUTDOWN_TIMEOUT
秒后仍处于活动状态的任何剩余连接。(server.closeAllConnections
)
如果您想自定义此行为,可以使用 自定义服务器。
您可以侦听 sveltekit:shutdown
事件,该事件在 HTTP 服务器关闭所有连接后发出。与 Node 的 exit
事件不同,sveltekit:shutdown
事件支持异步操作,并且在所有连接关闭时始终发出,即使服务器有悬挂的工作(如打开的数据库连接)。
var process: NodeJS.Process
process.NodeJS.Process.on(event: string | symbol, listener: (...args: any[]) => void): NodeJS.Process (+12 overloads)
Adds the listener
function to the end of the listeners array for the event
named eventName
. No checks are made to see if the listener
has already
been added. Multiple calls passing the same combination of eventName
and
listener
will result in the listener
being added, and called, multiple times.
server.on('connection', (stream) => {
console.log('someone connected!');
});
Returns a reference to the EventEmitter
, so that calls can be chained.
By default, event listeners are invoked in the order they are added. The emitter.prependListener()
method can be used as an alternative to add the
event listener to the beginning of the listeners array.
import { EventEmitter } from 'node:events';
const myEE = new EventEmitter();
myEE.on('foo', () => console.log('a'));
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
// b
// a
on('sveltekit:shutdown', async (reason: any
reason) => {
await jobs.stop();
await db.close();
});
参数 reason
具有以下值之一
SIGINT
- 关闭是由SIGINT
信号触发的SIGTERM
- 关闭由SIGTERM
信号触发IDLE
- 关闭由IDLE_TIMEOUT
触发
套接字激活
如今大多数 Linux 操作系统都使用名为 systemd 的现代进程管理器来启动服务器并运行和管理服务。您可以配置服务器分配一个套接字,并根据需要启动和扩展您的应用程序。这被称为 套接字激活。在这种情况下,操作系统会将两个环境变量传递给您的应用程序——LISTEN_PID
和 LISTEN_FDS
。然后,适配器将在文件描述符 3 上监听,该描述符引用您需要创建的 systemd 套接字单元。
您仍然可以在 systemd 套接字激活中使用
envPrefix
。LISTEN_PID
和LISTEN_FDS
始终在没有前缀的情况下读取。
要利用套接字激活,请按照以下步骤操作。
- 将您的应用程序作为 systemd 服务 运行。它可以直接在主机系统上运行,也可以在容器内运行(例如,使用 Docker 或 systemd 可移植服务)。如果您另外将
IDLE_TIMEOUT
环境变量传递给您的应用程序,则在IDLE_TIMEOUT
秒内没有请求时,它将优雅地关闭。当新的请求到来时,systemd 会自动重新启动您的应用程序。
[Service]
Environment=NODE_ENV=production IDLE_TIMEOUT=60
ExecStart=/usr/bin/node /usr/bin/myapp/build
- 创建一个配套的 套接字单元。适配器仅接受单个套接字。
[Socket]
ListenStream=3000
[Install]
WantedBy=sockets.target
- 确保 systemd 已识别这两个单元,方法是运行
sudo systemctl daemon-reload
。然后启用开机启动套接字并立即启动它,使用sudo systemctl enable --now myapp.socket
。然后,一旦向localhost:3000
发出第一个请求,应用程序就会自动启动。
自定义服务器
适配器在您的构建目录中创建两个文件——index.js
和 handler.js
。运行 index.js
——例如,如果您使用默认构建目录,则运行 node build
——将在配置的端口上启动服务器。
或者,您可以导入 handler.js
文件,该文件导出一个适用于 Express、Connect 或 Polka(甚至只是内置的 http.createServer
)的处理程序,并设置您自己的服务器
import { import handler
handler } from './build/handler.js';
import import express
express from 'express';
const const app: any
app = import express
express();
// add a route that lives separately from the SvelteKit app
const app: any
app.get('/healthcheck', (req, res) => {
res: any
res.end('ok');
});
// let SvelteKit handle everything else, including serving prerendered pages and static assets
const app: any
app.use(import handler
handler);
const app: any
app.listen(3000, () => {
var console: Console
The console
module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.
- A global
console
instance configured to write to process.stdout
and
process.stderr
. The global console
can be used without calling require('console')
.
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O
for
more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to stdout
with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
log('listening on port 3000');
});