# @formio/appserver-core 中文文档

规范地址：https://npmcn.com/package/%40formio/appserver-core/

版本：2\.26\.4
npm 元数据更新时间：2026-11-06T23:01:04.715Z
中文译文更新时间：2026-11-15T09:11:16.761Z
软件包许可：OSL-3\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40formio/appserver-core
原文对照：https://npmcn.com/package/%40formio/appserver-core/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：7.1 MB，85 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.0\.0
- 运行依赖：23 个
- 首次发布：2023-04-26T17:28:12.938Z
- 最新版本发布：2026-11-06T23:01:04.510Z
- 近 30 天下载量：5511（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：132（近 12 个月 49 个）

## 中文简介

Form.io应用程序服务器是用于服务单个项目模板(包括表格,资源,角色等)的表演者运行时间应用程序服务器,位于一个部署的端口. 目标是实现快速的 单一租户部署

## 安装

```sh
npm install @formio/appserver-core
```

也可以使用：`pnpm add @formio/appserver-core`、`yarn add @formio/appserver-core`、`bun add @formio/appserver-core`

## README

## Form.io 应用程序服务器 - 核心

Form.io应用程序服务器是用于服务单个项目模板(包括表格,资源,角色等)的表演者运行时间应用程序服务器,位于一个部署的端口. 目标是实现快速的单一租户部署,在您希望管理统一地点内所有表格和资源的地方,但将租户数据存储在自己的数据库中.

此库是 Form.io 应用程序服务器的企业核心. 它打算与@formio/appserver 库同时使用.

更多信息,请参见: [https://github.com/formio/appserver 页面存档备份,存于互联网档案馆](https://github.com/formio/appserver)

### 许可证发放

企业项目需要持有许可证 `appserver` 选项; 通用代理网关(UAG)特性需要 `uag` 选项,包括 `appserver`。许可证配置的环境变量与 Form.io Entertainment 和 PDF 服务器相同,因此一个许可证可以运行全部.

Form.io主机服务项目(a) `https:` 结束点 `form.io` 或它的子域,例如 `https://myproject.form.io` 或者说 `https://api.form.io/project/<id>`)不需要许可证:它运行在Form.io's下,作为企业号版,并且允许Agentic Formflow(理由) `hosted`) (中文(简体) ). 当应用服务器拥有自己的数据库时,该豁免不适用(`MONGO`),当 TLS 证书验证关闭时(`NODE_TLS_REJECT_UNAUTHORIZED=0`),或时 `NODE_EXTRA_CA_CERTS`, (中文(简体) ), `NODE_USE_SYSTEM_CA`, (中文(简体) ), `--use-system-ca` 或者说 `--use-openssl-ca` 已经设定。 自营企业的部署总是需要许可证.

| 变量 | 配置 | 说明 |
| --- | --- | --- |
| 英国语NAME |  | 一个Form.io许可证密钥。 为企业服务器签发的密钥由Form.io许可证服务器验证;离线许可证由本地验证. |
| _(服务器本身,例如 `UAG_LICENSE` 或者说 `APPSERVER_LICENSE`(中文(简体) )_ | `license`, (中文(简体) ), `licenseName` | 服务器自己的许可密钥,同样经过验证. `licenseName` 是它来自的变量,由哪个消息命名它. |
| 缩写 | `licenseRemote` | 设定为 `true` 当密钥是离线许可时, 所以许可证服务器从不联系, 对于任何密钥. |
| 服务器 | `licenseServer` | 验证在线密钥的许可服务器: Form.io的(form.io)之一`https://*.form.io`) (中文(简体) ). 默认为 `https://license.form.io`。 。 。 . |
|  | `licenseType` | 许可证服务器的用法类型计算此服务器的用法, 例如 `uagServer`默认为 `appServer`. 见下文. |
|  | `licenseFeature` | 服务器需要运行的特性, 例如 `uag`默认为 `appserver`. 见下文. |

一个特征是,当任一键为项目的终点授予它,所以,一个表格.io许可证与 `uag` 选项在 `LICENSE_KEY` 本身就足够了,服务器自己的密钥只能添加到它上. `LICENSE_KEY` 仅在服务器本身的密钥丢失、无法使用或缺少时进行校验 `uag` 对于终点,所以一个部署 它自己的钥匙足够 从来没有发送 `LICENSE_KEY` 到许可服务器。 每把钥匙都靠自己来验证:一把失败会让对方的结果完好无损. 当两个特性都没有被许可时,其理由按其变量命名每个密钥.

向许可证服务器报告在线密钥 `appServer` 使用类型,每个项目终点一个环境,因此其范围必须包括 `appServer`设置的服务器 `licenseType` 改为在该类别下报告。 一个设置的服务器 `licenseFeature` 需要这一特点,而不是 `appserver` 装入工程。 无人机集 `licenseType: 'uagServer'` 财务报告和审定财务报表 `licenseFeature: 'uag'`,因此它运行在许可证服务器接受的在线密钥上 `uagServer` (根据许可证计算) `uagServers`),或带有以下内容的离线许可证: `uag` 选项,为它所配置的项目服务 `appserver` 选项本身并不运行。 其条款每15分钟再次检查一次。 如果无法到达许可服务器,服务器继续按它最后一次确认的条件运行,从确认开始12小时;在许可的特性关闭后,直到可以再次到达.

在线密钥未验证时 `NODE_TLS_REJECT_UNAUTHORIZED=0`, (中文(简体) ), `NODE_EXTRA_CA_CERTS`, (中文(简体) ), `NODE_USE_SYSTEM_CA=1`, (中文(简体) ), `--use-openssl-ca` 或者说 `--use-system-ca` 设置; 使用离线许可证(`LICENSE_REMOTE`这里.

一旦12小时用完,或在重启之后,企业号项目在许可证服务器确认许可证之前不会加载.

### 模块

`server.use(module)` 添加一个模块:它的配置,动作,钩子,提供者,处理器,插件类型和插件,下面还有它的模块密钥. 它还需要一份模块清单,依次使用,以便: `server.use([first, second])`。 。 。 .

```js
server.use({
    name: 'word-count', title: 'Word count', version: '1.0.0', apiVersion: 1,
    settings: (config, env) => ({ max: Number(config.wordCount?.max ?? env.WORD_COUNT_MAX ?? 1000) }),
    routes: {
        form: {
            'POST /words/count': {
                handler: (req, res, api) => {
                    const words = String(req.body?.text || '').split(/\s+/).filter(Boolean).length;
                    if (words > api.settings.max) throw api.errors.create(413, `At most ${api.settings.max} words.`, 'too_many_words');
                    return { words };
                }
            }
        }
    },
    components: [{ type: 'wordcount', script: new URL('./dist/wordcount.js', import.meta.url) }],
    initialize: (api) => api.log.info(`at most ${api.settings.max} words`),
    plugins: [/* ... */]
});
```

-   **身份证明.** `name` (小写字母和数字,单词加上 `-`, (中文(简体) ), `title`, (中文(简体) ), `version` 财务报告和审定财务报表 `apiVersion`,该模块的 API 版本被写到对面。 一个模块与 `settings`, (中文(简体) ), `routes`, (中文(简体) ), `components`, (中文(简体) ), `initialize`, (中文(简体) ), `close` 函数 `pluginTypes` 需要一个 `name` 还有一个 `apiVersion`; 服务器不提供停止启动的API版本. `host` 将服务器命名为模块需要( n)`'uag'`:其他服务器在启动时拒绝. 一个模块 `name` 已使用不再使用;其另一个版本停止启动。 一个命名于 `config.modules.disabled` 未使用. `use()` 使用 ES 模块命名空间( S)`require()` a 默认导出.
-   **`settings(config, env)`** 在项目加载前,使用服务器的配置和环境,称为一次。 它返回一个普通对象(从不承诺),即 `api.settings`,冷冻;一个会抛出停止启动的错误,命名模块。 模块键在之前使用 `router()` 或者说 `initialize()`;一个用后停止启动.
-   **`routes.form`** 地图 `"<METHOD> /<path>"` 改为 `{ name?, access?, rateLimit?, handler(req, res, api) }`每张表格上挂有 `formRoutes` (见下文). `name` (默认: 模块的名称) 是主机速率限制的操作, 并且 `rateLimit: { limit, windowMs }` 默认操作员设置的覆盖。 接线员跑之前 呼叫员需要一个 `access` 关于表格上提交的表格:默认 `['create', 'update']`· ; `access: false` 把支票交给处理者. `req.form` 是窗体( e)`id`, (中文(简体) ), `name`, (中文(简体) ), `path`, (中文(简体) ), `title`,以及 `definition`,它的JSON, , `req.auth` 打电话者和 `req.signal` 当客户端消失时中止 。 操作者回答,或返回 JSON 回答,或扔 `api.errors.create(status, message, code)`任何其它错误被回答500, 没有细节, 处理器开始后的一个错误 以一个 `failed` 活动。 有两个模块可能不会定义相同的路由(与之相匹配的快递:大小写不敏感,没有后继斜线),一个路由可能不会使用窗体自己的路由(S`/`, (中文(简体) ), `/submission`, (中文(简体) ), `/exists`, (中文(简体) ), `/action`, (中文(简体) ), `/actions`和那些宿主加起来.
-   **`components`**: formio.js组件, `{ type, script, style? }` 作为文件路径或文件 URL. `script` 是一个经典的浏览器脚本,可以注册组件(已构建,而不是ES模块):服务器在启动时解析,并拒绝不解析,因为浏览器将每个组件都用一个脚本来获取. 它检查文件是否存在,没有两个模块定义一个类型,并保存在其中 `server.modules.components()`;宿主为他们服务.
-   **`pluginTypes`** 可能是模块的API的一个函数, `(api) => [...]`,用于需要它的插件类型.
-   **`initialize(api)`** 运行一次,在插件启动后,在任何请求之前;错误停止启动. **`close(api)`** 当服务器被销毁时运行( r)`await server.destroy()`),按倒序使用模块.
-   **列表(上册).** 一个模块 `apiVersion` 列在 `GET {project}/plugins` 作为 `module:<name>`,带有路径和组件类型,从未设置过.

### 模块 API

一个模块得到一个 `api`,第1版的路线, `initialize`, (中文(简体) ), `close` 函数 `pluginTypes`数字 :

| 成员 | 它会做什么 |
| --- | --- |
| `apiVersion`, (中文(简体) ), `name`, (中文(简体) ), `settings` | 模块的API版本,名称和解析设置. |
| `host` | 运行它的服务器 : `{ name, version }` (单位:千美元)`appserver`,或东道主自己的名字). |
| `log.info`, (中文(简体) ), `log.warn`, (中文(简体) ), `log.error` | 以模块名称为前缀的日志行. |
| `plugins.get(type, name)`, (中文(简体) ), `plugins.list(type)`, (中文(简体) ), `plugins.settings(type, name)` | 启用的插件和插件的操作员设置 . |
| `requireAccess(auth, form, methods)` | 投出403 除非呼叫者拥有其中之一 `methods` 在表格的提交. |
| `files.read(form, value, auth, { maxBytes, component, signal })` | 一个被存储的文件的字节,随呼叫者的证书和组件的存储检查一起读取. |
| `forms.componentAt(form, path)`, (中文(简体) ), `forms.componentByKey(form, key)` | 存储窗体的一个组件,通过数据路径(忽略了行索引)或密钥. |
| `errors.create(status, message, code)`, (中文(简体) ), `errors.is(err)` | 一个错误用该状态、消息和代码回答 . |
| `stream(req, res, run, { heartbeatMs })` | 答复 `{ result }` 带什么 `run({ signal, progress })` 返回,或向接受 `text/event-stream`, (中文(简体) ), `progress` 事件,然后 `done` 或者说 `failed`。 。 。 . |

一个主机服务器扩展了模块:一个子类可以覆盖这些.

| 覆盖 | 它的设定 |
| --- | --- |
| `hostName`, (中文(简体) ), `hostVersion` | 服务器名称, 模块需要使用 `host`,及其版本(`api.host`) (中文(简体) ). |
| `moduleApiVersions` | 服务器提供的API版本(`[1]`) (中文(简体) ). |
| `createModuleApi(module)` | API,每个模块一个: `{ ...super.createModuleApi(module), ...more }`。一个东道主会增加成员,但不会删除成员. |
| `moduleClaims(definition)` | 一个模块还声称,其他任何人都不能(如主机的MCP工具)作为标签; `server.modules.claim(label, owner)` 记录服务器本身. |
| `reservedRouteNames` | 路由名称(速率限制操作)模块可能不取. |
| `moduleRouteHandlers(project, route, module)` | `{ before, wrap }`: 在每个模块路径之前的中间软件( 呼叫器检查、 身体限制、 请求 id) , 以及环绕其运行的包装器( 速率限制由 `route.name`,错误形状). |
| `moduleErrorBody(req, err)` | 机体一个失败的路径答案,和一个 `failed` 事件载体( e)`{ status, error, code }`) (中文(简体) ). |
| `reservedFormPaths` | 第一个路径段模块路由可能无法使用. |

一个插件可以给定义其类型的模块命名 `module` (单位:千美元)`module: '@scope/package/modules/name'`:当该类型缺失时,启动会说使用该模块.

### 窗体路线

`routes.form` 是模块在每个窗体上添加路由的通常方式。 在它下面,模块可以将任何快取路由器添加到每个形式上,并带有 `formRoutes`: 快速路由器(或 `(req, res, next)` 中间软件),或其中的列表,被挂入到每个窗体的路径上,没有访问权限检查,冲突检查或主机中间软件.

```js
const { Router } = require('express');

const routes = Router();
routes.post('/echo', (req, res) => res.json({ form: req.form.form.name, user: req.auth?.user?._id }));

server.use({ formRoutes: routes });
```

-   路由器按其路径安装在每个表格的路线上(`/{formPath}/echo`并按其编号`/form/{formId}/echo`),包括管理员在内的每个呼叫者,在表格本身的提供者和提交路线之前. `req.form` 是窗体和 `req.auth` 呼叫者,已经认证。 路线检查了打电话者对它所作所为的访问.
-   团队下方的门户团队成员通过路径联系他们,从而产生提交需求(`team_write` 如代理操作; 以 id 表示, 仅作为管理员.
-   请求路由器不回答( 它呼叫 `next()`,对于一个它不服务的形式,比如说)继续到下一个路由器,然后继续到表单自己的路线,仿佛模块不存在一样. 路由器从 `req.form` 因此,他们总是看到现在的表格.
-   每个模块的路由器附加在 `use()` 命令,在模块的其余部分被应用后:一个失败的模块将不添加。 他们修过一次 `router()` 已构建服务器的路径: 在拒绝后添加更多 .
-   路由错误 `next(err)`,或者抛出,去服务器的错误处理,就像其他任何路径一样.
-   `use()` 拒绝 `formRoutes` 不属于路由器或中间软件(窗体的函数, `(form) => router`,没有。 信件以 [调试](https://www.npmjs.com/package/debug),将列表中的每个模块命名为 `source[i]`: 运行 `DEBUG=formio:*` 看到他们.

## 常见问题

### @formio/appserver-core 是什么？

Form\.io应用程序服务器是用于服务单个项目模板\(包括表格,资源,角色等\)的表演者运行时间应用程序服务器,位于一个部署的端口\. 目标是实现快速的 单一租户部署

### 如何安装 @formio/appserver-core？

在项目目录运行 npm install @formio/appserver-core，或使用 pnpm add / yarn add / bun add。

### @formio/appserver-core 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @formio/appserver-core 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @formio/appserver-core 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @formio/appserver-core 可以商用吗？

@formio/appserver-core 使用 OSL-3\.0 许可。声明的许可为 OSL-3\.0，请阅读许可原文确认使用条件。以上为概括，不构成法律意见，请以许可原文为准。

### @formio/appserver-core 的下载量有多少？

根据 npm 官方下载统计，@formio/appserver-core 在 2026/10/16 – 2026/11/14 这 30 天内被下载 5,511 次，日均约 184 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @formio/appserver-core 还在维护吗？

最新版本 2\.26\.4 发布于 2026/11/07（8 天前）；至今共发布 132 个版本，其中过去 12 个月发布了 49 个；首次发布于 2023/04/27。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

