跳至主要內容

Node 伺服器

要產生獨立的 Node 伺服器,請使用 adapter-node

用法

使用 npm i -D @sveltejs/adapter-node 安裝,然後將轉接器新增至你的 svelte.config.js

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

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

部署

首先,使用 npm run build 建置你的應用程式。這會在轉接器選項中指定的輸出目錄中建立生產伺服器,預設為 build

你需要輸出目錄、專案的 package.jsonnode_modules 中的生產相依性才能執行應用程式。生產相依性可以透過複製 package.jsonpackage-lock.json,然後執行 npm ci --omit dev 來產生(如果你的應用程式沒有任何相依性,則可以跳過此步驟)。然後你可以使用此命令啟動你的應用程式

node build

開發相依性將使用 Rollup 綑綁到你的應用程式中。要控制是否綑綁或外部化給定的套件,請將其分別放入你的 package.json 中的 devDependenciesdependencies 中。

壓縮回應

你通常會想要壓縮來自伺服器的回應。如果你已經在反向代理伺服器之後部署你的伺服器以進行 SSL 或負載平衡,通常在該層處理壓縮會產生更好的效能,因為 Node.js 是單執行緒的。

但是,如果你要建置自訂伺服器並想要在那裡新增壓縮中介軟體,請注意,我們建議使用 @polka/compression,因為 SvelteKit 會串流回應,而更流行的 compression 套件不支援串流,並且在使用時可能會導致錯誤。

環境變數

devpreview 中,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 上的連線。可以使用 PORTHOST 環境變數自訂這些連線

HOST=127.0.0.1 PORT=4000 node build

或者,可以將伺服器設定為接受指定 Socket 路徑上的連線。當使用 SOCKET_PATH 環境變數完成此操作時,將會忽略 HOSTPORT 環境變數。

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-protox-forwarded-host 是事實上的標準標頭,如果你使用反向代理伺服器(想想負載平衡器和 CDN),則會轉發原始通訊協定和主機。只有當你的伺服器位於受信任的反向代理伺服器之後時,才應設定這些變數;否則,用戶端可能會偽造這些標頭。

如果你的代理伺服器託管在非標準連接埠上,並且你的反向代理伺服器支援 x-forwarded-port,你也可以設定 PORT_HEADER=x-forwarded-port

如果 adapter-node 無法正確判斷你的部署的 URL,則在使用 表單操作 時可能會遇到此錯誤

禁止跨網站 POST 表單提交

ADDRESS_HEADER 和 XFF_DEPTH

傳遞給 Hook 和端點的 RequestEvent 物件包含一個 event.getClientAddress() 函式,該函式會傳回用戶端的 IP 位址。預設情況下,這是連線的 remoteAddress。如果你的伺服器位於一個或多個代理伺服器(例如負載平衡器)之後,則此值將包含最內層代理伺服器的 IP 位址,而不是用戶端的 IP 位址,因此我們需要指定一個 ADDRESS_HEADER 來從中讀取位址

ADDRESS_HEADER=True-Client-IP node build

標頭很容易被偽造。與 PROTOCOL_HEADERHOST_HEADER 一樣,在設定這些標頭之前,你應該知道你在做什麼

如果 ADDRESS_HEADERX-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) 的單位後綴來指定。例如,512K1M。預設值為 512kb。你可以使用值 Infinity(在轉接器的較舊版本中為 0)停用此選項,並在 handle 中實作自訂檢查,如果你需要更進階的功能。

SHUTDOWN_TIMEOUT

在收到 SIGTERMSIGINT 訊號後,強制關閉任何剩餘連線之前要等待的秒數。預設值為 30。在內部,轉接器會呼叫 closeAllConnections。請參閱優雅關閉以取得更多詳細資訊。

IDLE_TIMEOUT

當使用 systemd Socket 啟動時,IDLE_TIMEOUT 指定在未收到任何請求時,應用程式自動進入休眠狀態的秒數。如果未設定,則應用程式會持續執行。請參閱Socket 啟動以取得更多詳細資訊。

選項

可以使用各種選項設定轉接器

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 會在建立後在本地啟動伺服器。

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

優雅關閉

預設情況下,當收到 SIGTERMSIGINT 訊號時,adapter-node 會優雅地關閉 HTTP 伺服器。它會

  1. 拒絕新的請求 (server.close)
  2. 等待已經發出但尚未收到回應的請求完成,並在連線閒置後關閉連線 (server.closeIdleConnections)
  3. 最後,在經過 SHUTDOWN_TIMEOUT 秒後,關閉所有仍然處於活動狀態的連線。(server.closeAllConnections

如果您想要自訂此行為,可以使用自訂伺服器

您可以監聽 sveltekit:shutdown 事件,該事件會在 HTTP 伺服器關閉所有連線後發出。與 Node 的 exit 事件不同,sveltekit:shutdown 事件支援非同步操作,並且總是在所有連線關閉時發出,即使伺服器有未完成的工作,例如開啟的資料庫連線。

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 具有以下其中一個值:

  • SIGINT - 關閉是由 SIGINT 訊號觸發的
  • SIGTERM - 關閉是由 SIGTERM 訊號觸發的
  • IDLE - 關閉是由 IDLE_TIMEOUT 觸發的

Socket 啟動

現今大多數 Linux 作業系統都使用名為 systemd 的現代程序管理器來啟動伺服器並執行和管理服務。您可以配置您的伺服器以分配一個 socket 並根據需求啟動和擴展您的應用程式。這稱為socket 啟動。在這種情況下,作業系統會將兩個環境變數傳遞給您的應用程式 — LISTEN_PIDLISTEN_FDS。然後,adapter 會監聽檔案描述符 3,它指向您必須建立的 systemd socket 單元。

您仍然可以將 envPrefix 用於 systemd socket 啟動。LISTEN_PIDLISTEN_FDS 始終在沒有前綴的情況下讀取。

要利用 socket 啟動,請按照以下步驟操作。

  1. 將您的應用程式作為systemd 服務執行。它可以直接在主機系統上或在容器內(例如使用 Docker 或 systemd 可攜式服務)執行。如果您額外將 IDLE_TIMEOUT 環境變數傳遞給您的應用程式,如果 IDLE_TIMEOUT 秒內沒有請求,它將會優雅地關閉。當有新的請求進來時,systemd 會自動再次啟動您的應用程式。
/etc/systemd/system/myapp
[Service]
Environment=NODE_ENV=production IDLE_TIMEOUT=60
ExecStart=/usr/bin/node /usr/bin/myapp/build
  1. 建立一個配套的socket 單元。adapter 只接受單個 socket。
/etc/systemd/system/myapp
[Socket]
ListenStream=3000

[Install]
WantedBy=sockets.target
  1. 執行 sudo systemctl daemon-reload 以確保 systemd 已識別到這兩個單元。然後使用 sudo systemctl enable --now myapp.socket 在開機時啟用 socket 並立即啟動它。一旦對 localhost:3000 發出第一個請求,應用程式就會自動啟動。

自訂伺服器

adapter 會在您的建置目錄中建立兩個檔案 — index.jshandler.js。如果您使用預設的建置目錄,執行 index.js — 例如 node build — 將會在配置的端口上啟動伺服器。

或者,您可以匯入 handler.js 檔案,該檔案會匯出一個適用於 ExpressConnectPolka(甚至只是內建的 http.createServer)的處理程式,並設定您自己的伺服器。

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');
});

在 GitHub 上編輯此頁面