要生成一个独立的 Node 服务器,请使用[`adapter-node`](https://github.com/sveltejs/kit/tree/main/packages/adapter-node)。 ## 使用 安装 `npm i -D @sveltejs/adapter-node` 后,将适配器添加到您的`svelte.config.js`中: ```js // @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-node'; export default { kit: { adapter: adapter() } }; ``` ## 部署 首先,使用`npm run build`构建您的应用。这将创建在适配器选项中指定的输出目录的生产服务器,默认为`build`。 您需要输出目录、项目的`package.json`以及`node_modules`中的生产依赖来运行应用程序。可以通过复制`package.json`和`package-lock.json`并运行`npm ci --omit dev`来生成生产依赖(如果您的应用程序没有依赖项,可以跳过此步骤)。然后,您可以使用以下命令启动您的应用程序: `node 编译` 开发依赖将被打包到您的应用中,使用[Rollup](https://rollupjs.org)。要控制是否将某个包打包或外部化,请将其分别放置在您的`package.json`中的`devDependencies`或`dependencies`中。 ### 压缩响应 通常您会希望压缩来自服务器的响应。如果您已经在部署使用 SSL 或负载均衡的反向代理服务器,由于 Node.js 是单线程的,因此在那个层面处理压缩通常可以获得更好的性能。 然而,如果您正在构建一个[自定义服务器](#Custom-server)并且确实想在那里添加压缩中间件,请注意我们建议使用[`@polka/compression`](https://www.npmjs.com/package/@polka/compression),因为 SvelteKit 流式传输响应,而更受欢迎的`compression`包不支持流式传输,可能会在使用时引发错误。 ## 环境变量 在`dev`和`preview`中,SvelteKit 将从您的`.env`文件(或`.env.local`,或`.env.[mode]`,[由 Vite 确定](https://vitejs.dev/guide/env-and-mode.html#env-files)。)中读取环境变量。 在生产中,`.env` 文件不会被自动加载。要实现这一点,请在您的项目中安装 `dotenv`... `npm 安装 dotenv` ...在运行构建的应用程序之前调用它: ```bash node +++-r dotenv/config+++ build ``` 如果您使用 Node.js v20.6+,可以使用[`--env-file`](https://nodejs.org/en/learn/command-line/how-to-read-environment-variables-from-nodejs)标志: ```bash node +++--env-file=.env+++ build ``` ### `端口`,`主机`和`SOCKET_PATH` 默认情况下,服务器将在`0.0.0.0`上使用端口 3000 接受连接。这些可以通过`PORT`和`HOST`环境变量进行自定义: ```bash HOST=127.0.0.1 PORT=4000 node build ``` 另外,服务器可以被配置为在指定的套接字路径上接受连接。当使用 `SOCKET_PATH` 环境变量执行此操作时,将忽略 `HOST` 和 `PORT` 环境变量。 ```bash SOCKET_PATH=/tmp/socket node build ``` ### `ORIGIN`,`PROTOCOL_HEADER`,`HOST_HEADER`和`PORT_HEADER` HTTP 不提供一种可靠的方法让 SvelteKit 知道当前正在请求的 URL。告诉 SvelteKit 应用正在被服务的最简单方法是将 `ORIGIN` 环境变量设置: ```bash 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: ```bash PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build ``` > \[注意\] [`x-forwarded-proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) 和 [`x-forwarded-host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) 是事实上的标准头信息,用于在您使用反向代理(例如负载均衡器和 CDN)时转发原始协议和主机。只有当您的服务器位于受信任的反向代理后面时,才应设置这些变量;否则,客户端可能会伪造这些头信息。 > > 如果您在非标准端口上托管代理且反向代理支持`x-forwarded-port`,您还可以设置`PORT_HEADER=x-forwarded-port`。 如果 `适配器节点`无法正确确定您的部署的 URL,您在使用[表单操作](form-actions)时可能会遇到此错误: > \[注意\] 禁止跨站 POST 表单提交 ### `地址头` 和 `xff 深度` The [`RequestEvent`](@sveltejs-kit#RequestEvent) 对象传递给钩子和端点时,包括一个 `event.getClientAddress()` 函数,该函数返回客户端的 IP 地址。默认情况下,这是连接的 `remoteAddress`。如果您的服务器位于一个或多个代理(如负载均衡器)后面,则此值将包含最内层的代理的 IP 地址而不是客户端的,因此我们需要指定一个 `ADDRESS_HEADER` 来读取地址: ```bash ADDRESS_HEADER=True-Client-IP node build ``` > \[!注意\] 标题很容易被伪造。例如,与 `PROTOCOL_HEADER` 和 `HOST_HEADER` 一样,在设置这些之前,你应该 [了解你在做什么](https://adam-p.ca/blog/2022/03/x-forwarded-for/)。 如果 `ADDRESS_HEADER` 是 `X-Forwarded-For`,则头部值将包含以逗号分隔的 IP 地址列表。应通过 `XFF_DEPTH` 环境变量指定在您的服务器前面有多少个受信任的代理。例如,如果有三个受信任的代理,代理 3 将转发原始连接的地址以及前两个代理的地址: ``` , , ``` 一些指南会告诉您读取最左边的地址,但这样做会使您[容易受到欺骗](https://adam-p.ca/blog/2022/03/x-forwarded-for/): ``` , , , ``` 我们从右侧读取,考虑到可信代理的数量。在这种情况下,我们将使用`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`](https://nodejs.org/api/http.html#servercloseallconnections)。有关更多详细信息,请参阅 [优雅关闭](#Graceful-shutdown)。 ### `空闲超时` 当使用 systemd 套接字激活时,`IDLE_TIMEOUT`指定了在收到无请求后应用自动休眠的秒数。如果没有设置,应用将连续运行。请参阅[套接字激活](#Socket-activation)获取更多详细信息。 ## 选项 适配器可以配置为各种选项: ```js // @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-node'; export default { kit: { adapter: adapter({ // default options are shown out: 'build', precompress: true, envPrefix: '' }) } }; ``` ### 出 服务器构建目录。默认为 `build` — 即 `node build` 将在创建后本地启动服务器。 ### 预压缩 启用使用 gzip 和 brotli 对资源和预渲染页面进行预压缩。默认为`true`。 ### envPrefix 如果您需要更改用于配置部署的环境变量名称(例如,为了避免与您无法控制的环境变量冲突),您可以指定一个前缀: ```js envPrefix: 'MY_CUSTOM_'; ``` ```bash MY_CUSTOM_HOST=127.0.0.1 \ MY_CUSTOM_PORT=4000 \ MY_CUSTOM_ORIGIN=https://my.site \ node build ``` ## 优雅关机 默认情况下,当接收到 `adapter-node` 或 `SIGTERM` 或 `SIGINT` 信号时,它会优雅地关闭 HTTP 服务器。它将: 1. 拒绝新的请求([`server.close`](https://nodejs.org/api/http.html#serverclosecallback)) 2. 等待已完成但尚未收到响应的请求完成,并在它们变为空闲时关闭连接([`server.closeIdleConnections`](https://nodejs.org/api/http.html#servercloseidleconnections)) 3. 最后,关闭在[`SHUTDOWN_TIMEOUT`](#Environment-variables-SHUTDOWN_TIMEOUT)秒后仍然活跃的任何剩余连接。([`server.closeAllConnections`](https://nodejs.org/api/http.html#servercloseallconnections)) > \[!注意\] 如果您想自定义此行为,可以使用[自定义服务器](#Custom-server)。 您可以在 HTTP 服务器关闭所有连接后监听 `sveltekit:shutdown` 事件。与 Node 的 `exit` 事件不同,`sveltekit:shutdown` 事件支持异步操作,并且当所有连接关闭时始终会触发,即使服务器有悬挂的工作,如打开的数据库连接。 ```js // @errors: 2304 process.on('sveltekit:shutdown', async (reason) => { await jobs.stop(); await db.close(); }); ``` 参数 `reason` 有以下几种值: * `SIGINT` - 关闭操作由 `SIGINT` 信号触发 * `SIGTERM` - 关闭操作由 `SIGTERM` 信号触发 * `空闲` - 关闭由 [`空闲超时`](#Environment-variables-IDLE_TIMEOUT) 触发 ## 套接字激活 大多数 Linux 操作系统今天使用名为 systemd 的现代进程管理器来启动服务器并运行和管理服务。您可以将服务器配置为分配套接字并在需要时启动和扩展您的应用程序。这被称为[套接字激活](http://0pointer.de/blog/projects/socket-activated-containers.html)。在这种情况下,操作系统将传递两个环境变量到您的应用程序中——`LISTEN_PID`和`LISTEN_FDS`。然后适配器将在文件描述符 3 上监听,该描述符指向您必须创建的系统 d 套接字单元。 > \[注意\] 您仍然可以使用 [`envPrefix`](#Options-envPrefix) 与 systemd 网络套接字激活一起使用。 `LISTEN_PID` 和 `LISTEN_FDS` 总是带前缀读取。 利用套接字激活,请按照以下步骤操作。 1. 运行您的应用作为[systemd 服务](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html)。它可以直接在主机系统上运行,或者在容器内运行(例如使用 Docker 或 systemd 便携式服务)。如果您向应用传递一个[`IDLE_TIMEOUT`](#Environment-variables-IDLE_TIMEOUT)环境变量,当没有请求持续`IDLE_TIMEOUT`秒时,它将优雅地关闭。当有新请求到来时,systemd 将自动重新启动您的应用。 ```ini /// file: /etc/systemd/system/myapp.service [Service] Environment=NODE_ENV=production IDLE_TIMEOUT=60 ExecStart=/usr/bin/node /usr/bin/myapp/build ``` 2. 创建一个配套的[套接字单元](https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html)。适配器仅接受一个套接字。 ```ini /// file: /etc/systemd/system/myapp.socket [Socket] ListenStream=3000 [Install] WantedBy=sockets.target ``` 3. 确保 systemd 已识别这两个单元,通过运行`sudo systemctl daemon-reload`。然后,在启动时启用套接字并立即使用 `sudo systemctl enable --now myapp.socket` 启动它。一旦对`localhost:3000`发起第一个请求,应用程序将自动启动。 ## 自定义服务器 适配器在您的构建目录中创建两个文件——`index.js`和`handler.js`。运行`index.js`——例如`node build`,如果您使用默认的构建目录——将在配置的端口上启动服务器。 或者,您可以导入 `handler.js` 文件,该文件导出一个适用于与 [Express](https://github.com/expressjs/express)、[Connect](https://github.com/senchalabs/connect) 或 [Polka](https://github.com/lukeed/polka)(甚至只是内置的 [`http.createServer`](https://nodejs.org/dist/latest/docs/api/http.html#httpcreateserveroptions-requestlistener))一起使用的处理器,并设置自己的服务器: ```js // @errors: 2307 7006 /// file: my-server.js 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'); }); ```