Skip to main content

Node 服务器

要生成独立的 Node 服务器,请使用 adapter-node

¥To generate a standalone Node server, use adapter-node.

用法(Usage)

¥Usage

使用 npm i -D @sveltejs/adapter-node 安装,然后将适配器添加到你的 svelte.config.js

¥Install with npm i -D @sveltejs/adapter-node, then add the adapter to your svelte.config.js:

svelte.config
import import adapteradapter from '@sveltejs/adapter-node';

export default {
	
kit: {
    adapter: any;
}
kit
: {
adapter: anyadapter: import adapteradapter() } };

部署(Deploying)

¥Deploying

首先,使用 npm run build 构建你的应用。这将在适配器选项中指定的输出目录中创建生产服务器,默认为 build

¥First, build your app with npm run build. This will create the production server in the output directory specified in the adapter options, defaulting to build.

你需要输出目录、项目的 package.jsonnode_modules 中的生产依赖来运行应用。可以通过复制 package.jsonpackage-lock.json 然后运行 ​​npm ci --omit dev 来生成生产依赖(如果你的应用没有任何依赖,则可以跳过此步骤)。然后,你可以使用以下命令启动你的应用:

¥You will need the output directory, the project’s package.json, and the production dependencies in node_modules to run the application. Production dependencies can be generated by copying the package.json and package-lock.json and then running npm ci --omit dev (you can skip this step if your app doesn’t have any dependencies). You can then start your app with this command:

node build

开发依赖将使用 Rollup 打包到你的应用中。要控制给定包是打包还是外部化,请将其分别放在 package.json 中的 devDependenciesdependencies 中。

¥Development dependencies will be bundled into your app using Rollup. To control whether a given package is bundled or externalised, place it in devDependencies or dependencies respectively in your package.json.

压缩响应(Compressing responses)

¥Compressing responses

你通常需要压缩来自服务器的响应。如果你已经在反向代理后面部署服务器以进行 SSL 或负载平衡,由于 Node.js 是单线程的,因此在该层处理压缩通常会带来更好的性能。

¥You will typically want to compress responses coming from the server. If you are already deploying your server behind a reverse proxy for SSL or load balancing, it typically results in better performance to also handle compression at that layer since Node.js is single-threaded.

但是,如果你正在构建 自定义服务器 并且确实想在那里添加压缩中间件,请注意,我们建议使用 @polka/compression,因为 SvelteKit 流式传输响应,而更流行的 compression 包不支持流式传输,使用时可能会导致错误。

¥However, if you’re building a custom server and do want to add a compression middleware there, note that we would recommend using @polka/compression since SvelteKit streams responses and the more popular compression package does not support streaming and may cause errors when used.

环境变量(Environment variables)

¥Environment variables

devpreview 中,SvelteKit 将从你的 .env 文件(或 .env.local.env.[mode]由 Vite 确定)读取环境变量。

¥In dev and preview, SvelteKit will read environment variables from your .env file (or .env.local, or .env.[mode], as determined by Vite.)

在生产中,不会自动加载 .env 文件。为此,请在你的项目中安装 dotenv...

¥In production, .env files are not automatically loaded. To do so, install dotenv in your project...

npm install dotenv

...并在运行构建的应用之前调用它:

¥...and invoke it before running the built app:

node -r dotenv/config build

如果你使用 Node.js v20.6+,则可以改用 --env-file 标志:

¥If you use Node.js v20.6+, you can use the --env-file flag instead:

node --env-file=.env build

PORT、HOST 和 SOCKET_PATH(PORT, HOST and SOCKET_PATH)

¥PORT, HOST and SOCKET_PATH

默认情况下,服务器将使用端口 3000 接受 0.0.0.0 上的连接。这些可以使用 PORTHOST 环境变量进行定制:

¥By default, the server will accept connections on 0.0.0.0 using port 3000. These can be customised with the PORT and HOST environment variables:

HOST=127.0.0.1 PORT=4000 node build

或者,可以将服务器配置为接受指定套接字路径上的连接。当使用 SOCKET_PATH 环境变量完成此操作时,HOSTPORT 环境变量将被忽略。

¥Alternatively, the server can be configured to accept connections on a specified socket path. When this is done using the SOCKET_PATH environment variable, the HOST and PORT environment variables will be disregarded.

SOCKET_PATH=/tmp/socket node build

ORIGIN、PROTOCOL_HEADER、HOST_HEADER 和 PORT_HEADER(ORIGIN, PROTOCOL_HEADER, HOST_HEADER, and PORT_HEADER)

¥ORIGIN, PROTOCOL_HEADER, HOST_HEADER, and PORT_HEADER

HTTP 没有为 SvelteKit 提供可靠的方式来了解当前正在请求的 URL。告诉 SvelteKit 应用在哪里提供服务的最简单方法是设置 ORIGIN 环境变量:

¥HTTP doesn’t give SvelteKit a reliable way to know the URL that is currently being requested. The simplest way to tell SvelteKit where the app is being served is to set the ORIGIN environment variable:

ORIGIN=https://my.site node build

# or e.g. for local previewing and testing
ORIGIN=http://localhost:3000 node build

通过此方法,对 /stuff 路径名的请求将正确解析为 https://my.site/stuff。或者,你可以指定标头来告知 SvelteKit 有关请求协议和主机的信息,它可以从中构建原始 URL:

¥With this, a request for the /stuff pathname will correctly resolve to https://my.site/stuff. Alternatively, you can specify headers that tell SvelteKit about the request protocol and host, from which it can construct the origin URL:

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

如果你使用反向代理(例如负载平衡器和 CDN),x-forwarded-protox-forwarded-host 是事实上的标准标头,它们会转发原始协议和主机。你应该只在你的服务器位于受信任的反向代理后面时设置这些变量;否则,客户端可能会欺骗这些标头。

¥[!NOTE] x-forwarded-proto and x-forwarded-host are de facto standard headers that forward the original protocol and host if you’re using a reverse proxy (think load balancers and CDNs). You should only set these variables if your server is behind a trusted reverse proxy; otherwise, it’d be possible for clients to spoof these headers.

如果你在非标准端口上托管代理并且你的反向代理支持 x-forwarded-port,你也可以设置 PORT_HEADER=x-forwarded-port

¥If you’re hosting your proxy on a non-standard port and your reverse proxy supports x-forwarded-port, you can also set PORT_HEADER=x-forwarded-port.

如果 adapter-node 无法正确确定你部署的 URL,则在使用 表单操作 时可能会遇到此错误:

¥If adapter-node can’t correctly determine the URL of your deployment, you may experience this error when using form actions:

禁止跨站点 POST 表单提交

¥[!NOTE] Cross-site POST form submissions are forbidden

ADDRESS_HEADER 和 XFF_DEPTH(ADDRESS_HEADER and XFF_DEPTH)

¥ADDRESS_HEADER and XFF_DEPTH

传递给钩子和端点的 RequestEvent 对象包含一个返回客户端 IP 地址的 event.getClientAddress() 函数。默认情况下,这是连接的 remoteAddress。如果你的服务器位于一个或多个代理(例如负载平衡器)后面,则此值将包含最内层代理的 IP 地址而不是客户端的 IP 地址,因此我们需要指定一个 ADDRESS_HEADER 来读取地址:

¥The RequestEvent object passed to hooks and endpoints includes an event.getClientAddress() function that returns the client’s IP address. By default this is the connecting remoteAddress. If your server is behind one or more proxies (such as a load balancer), this value will contain the innermost proxy’s IP address rather than the client’s, so we need to specify an ADDRESS_HEADER to read the address from:

ADDRESS_HEADER=True-Client-IP node build

标头很容易被欺骗。与 PROTOCOL_HEADERHOST_HEADER 一样,你应该在设置这些之前 知道你在做什么

¥[!NOTE] Headers can easily be spoofed. As with PROTOCOL_HEADER and HOST_HEADER, you should know what you’re doing before setting these.

如果 ADDRESS_HEADERX-Forwarded-For,则标头值将包含以逗号分隔的 IP 地址列表。XFF_DEPTH 环境变量应指定服务器前面有多少个受信任的代理。例如如果有三个受信任的代理,代理 3 将转发原始连接和前两个代理的地址:

¥If the ADDRESS_HEADER is X-Forwarded-For, the header value will contain a comma-separated list of IP addresses. The XFF_DEPTH environment variable should specify how many trusted proxies sit in front of your server. E.g. if there are three trusted proxies, proxy 3 will forward the addresses of the original connection and the first two proxies:

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

某些指南会告诉你读取最左边的地址,但这会让你留下 易受欺骗

¥Some guides will tell you to read the left-most address, but this leaves you vulnerable to spoofing:

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

我们改为从右侧读取,考虑受信任代理的数量。在这种情况下,我们将使用 XFF_DEPTH=3

¥We instead read from the right, accounting for the number of trusted proxies. In this case, we would use XFF_DEPTH=3.

如果你需要读取最左边的地址(并且不关心欺骗) - 例如,提供地理定位服务,其中 IP 地址的真实性比可信性更重要,你可以通过检查应用中的 x-forwarded-for 标头来实现。

¥[!NOTE] If you need to read the left-most address instead (and don’t care about spoofing) — for example, to offer a geolocation service, where it’s more important for the IP address to be real than trusted, you can do so by inspecting the x-forwarded-for header within your app.

BODY_SIZE_LIMIT

在流式传输时接受的最大请求主体大小(以字节为单位)。主体大小也可以用千字节(K)、兆字节(M)或千兆字节(G)的单位后缀来指定。例如,512K1M。默认为 512kb。如果你需要更高级的功能,你可以使用值 Infinity(旧版本的适配器中为 0)禁用此选项,并在 handle 中实现自定义检查。

¥The maximum request body size to accept in bytes including while streaming. The body size can also be specified with a unit suffix for kilobytes (K), megabytes (M), or gigabytes (G). For example, 512K or 1M. Defaults to 512kb. You can disable this option with a value of Infinity (0 in older versions of the adapter) and implement a custom check in handle if you need something more advanced.

SHUTDOWN_TIMEOUT

在收到 SIGTERMSIGINT 信号后强制关闭任何剩余连接之前等待的秒数。默认为 30。适配器在内部调用 closeAllConnections。有关更多详细信息,请参阅 优雅关机

¥The number of seconds to wait before forcefully closing any remaining connections after receiving a SIGTERM or SIGINT signal. Defaults to 30. Internally the adapter calls closeAllConnections. See Graceful shutdown for more details.

IDLE_TIMEOUT

使用 systemd 套接字激活时,IDLE_TIMEOUT 指定在未收到任何请求后应用自动进入睡眠状态的秒数。如果未设置,应用将持续运行。有关更多详细信息,请参阅 套接字激活

¥When using systemd socket activation, IDLE_TIMEOUT specifies the number of seconds after which the app is automatically put to sleep when receiving no requests. If not set, the app runs continuously. See Socket activation for more details.

选项(Options)

¥Options

适配器可以配置各种选项:

¥The adapter can be configured with various options:

svelte.config
import import adapteradapter from '@sveltejs/adapter-node';

export default {
	
kit: {
    adapter: any;
}
kit
: {
adapter: anyadapter: import adapteradapter({ // default options are shown out: stringout: 'build', precompress: booleanprecompress: true, envPrefix: stringenvPrefix: '' }) } };

out

构建服务器的目录。它默认为 build — 即 node build 将在创建服务器后在本地启动服务器。

¥The directory to build the server to. It defaults to build — i.e. node build would start the server locally after it has been created.

precompress

启用使用 gzip 和 brotli 对资源和预渲染页面进行预压缩。它默认为 true

¥Enables precompressing using gzip and brotli for assets and prerendered pages. It defaults to true.

envPrefix

如果你需要更改用于配置部署的环境变量的名称(例如,为了与你无法控制的环境变量冲突),你可以指定前缀:

¥If you need to change the name of the environment variables used to configure the deployment (for example, to deconflict with environment variables you don’t control), you can specify a prefix:

envPrefix: 'MY_CUSTOM_';
MY_CUSTOM_HOST=127.0.0.1 \
MY_CUSTOM_PORT=4000 \
MY_CUSTOM_ORIGIN=https://my.site \
node build

优雅关机(Graceful shutdown)

¥Graceful shutdown

默认情况下,当收到 SIGTERMSIGINT 信号时,adapter-node 会正常关闭 HTTP 服务器。它将:

¥By default adapter-node gracefully shuts down the HTTP server when a SIGTERM or SIGINT signal is received. It will:

  1. 重命名:

    ¥reject new requests (server.close)

  2. 等待已发出但尚未收到响应的请求完成,并在连接空闲时关闭连接(server.closeIdleConnections

    ¥wait for requests that have already been made but not received a response yet to finish and close connections once they become idle (server.closeIdleConnections)

  3. 最后,关闭 SHUTDOWN_TIMEOUT 秒后仍处于活动状态的所有剩余连接。(server.closeAllConnections)

    ¥and finally, close any remaining connections that are still active after SHUTDOWN_TIMEOUT seconds. (server.closeAllConnections)

如果你想自定义此行为,可以使用 自定义服务器

¥[!NOTE] If you want to customize this behaviour you can use a custom server.

你可以监听 HTTP 服务器关闭所有连接后发出的 sveltekit:shutdown 事件。与 Node 的 exit 事件不同,sveltekit:shutdown 事件支持异步操作,并且始终在所有连接关闭时发出,即使服务器有悬而未决的工作(例如打开的数据库连接)。

¥You can listen to the sveltekit:shutdown event which is emitted after the HTTP server has closed all connections. Unlike Node’s exit event, the sveltekit:shutdown event supports asynchronous operations and is always emitted when all connections are closed even if the server has dangling work such as open database connections.

var process: NodeJS.Processprocess.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
@sincev0.1.101
@parameventName The name of the event.
@paramlistener The callback function
on
('sveltekit:shutdown', async (reason: anyreason) => {
await jobs.stop(); await db.close(); });

参数 reason 具有以下值之一:

¥The parameter reason has one of the following values:

  • SIGINT - 关闭由 SIGINT 信号触发

    ¥SIGINT - shutdown was triggered by a SIGINT signal

  • SIGTERM - 关闭由 SIGTERM 信号触发

    ¥SIGTERM - shutdown was triggered by a SIGTERM signal

  • IDLE - 关闭由 IDLE_TIMEOUT 触发

    ¥IDLE - shutdown was triggered by IDLE_TIMEOUT

套接字激活(Socket activation)

¥Socket activation

当今大多数 Linux 操作系统都使用名为 systemd 的现代进程管理器来启动服务器并运行和管理服务。你可以配置服务器以分配套接字并根据需要启动和扩展应用。这被称为 套接字激活。在这种情况下,操作系统将向你的应用传递两个环境变量 - LISTEN_PIDLISTEN_FDS。然后,适配器将监听文件描述符 3,它引用你必须创建的 systemd 套接字单元。

¥Most Linux operating systems today use a modern process manager called systemd to start the server and run and manage services. You can configure your server to allocate a socket and start and scale your app on demand. This is called socket activation. In this case, the OS will pass two environment variables to your app — LISTEN_PID and LISTEN_FDS. The adapter will then listen on file descriptor 3 which refers to a systemd socket unit that you will have to create.

你仍然可以将 envPrefix 与 systemd 套接字激活一起使用。LISTEN_PIDLISTEN_FDS 始终不带前缀读取。

¥[!NOTE] You can still use envPrefix with systemd socket activation. LISTEN_PID and LISTEN_FDS are always read without a prefix.

要利用套接字激活,请按照以下步骤操作。

¥To take advantage of socket activation follow these steps.

  1. 将你的应用作为 systemd 服务 运行。它可以直接在主机系统上运行,也可以在容器内运行(例如使用 Docker 或 systemd 可移植服务)。如果你另外将 IDLE_TIMEOUT 环境变量传递给你的应用,如果 IDLE_TIMEOUT 秒内没有请求,它将正常关闭。当有新请求进入时,systemd 将自动重新启动你的应用。

    ¥Run your app as a systemd service. It can either run directly on the host system or inside a container (using Docker or a systemd portable service for example). If you additionally pass an IDLE_TIMEOUT environment variable to your app it will gracefully shutdown if there are no requests for IDLE_TIMEOUT seconds. systemd will automatically start your app again when new requests are coming in.

/etc/systemd/system/myapp
[Service]
Environment=NODE_ENV=production IDLE_TIMEOUT=60
ExecStart=/usr/bin/node /usr/bin/myapp/build
  1. 创建随附的 套接字单元。适配器只接受一个套接字。

    ¥Create an accompanying socket unit. The adapter only accepts a single socket.

/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 发出第一个请求,应用将自动启动。

    ¥Make sure systemd has recognised both units by running sudo systemctl daemon-reload. Then enable the socket on boot and start it immediately using sudo systemctl enable --now myapp.socket. The app will then automatically start once the first request is made to localhost:3000.

自定义服务器(Custom server)

¥Custom server

适配器在你的构建目录中创建两个文件 - index.jshandler.js。运行 index.js — 例如 node build,如果你使用默认构建目录 — 将在配置的端口上启动服务器。

¥The adapter creates two files in your build directory — index.js and handler.js. Running index.js — e.g. node build, if you use the default build directory — will start a server on the configured port.

或者,你可以导入 handler.js 文件,该文件导出适用于 ExpressConnectPolka(甚至只是内置的 http.createServer)的处理程序并设置你自己的服务器:

¥Alternatively, you can import the handler.js file, which exports a handler suitable for use with Express, Connect or Polka (or even just the built-in http.createServer) and set up your own server:

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

const const app: anyapp = import expressexpress();

// add a route that lives separately from the SvelteKit app
const app: anyapp.get('/healthcheck', (req, res) => {

	res: anyres.end('ok');
});

// let SvelteKit handle everything else, including serving prerendered pages and static assets
const app: anyapp.use(import handlerhandler);

const app: anyapp.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
@seesource
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.

@sincev0.1.100
log
('listening on port 3000');
});