☰
在代码中嵌入 Prism HTTP Server:用 `@stoplight/prism-http-server` 将 OpenAPI 文档变成可编程的 Mock 服务
2026/10/13 3:05:03 网站建设 项目流程
  • 后端
  • 接口测试
  • 开发工具

【免费下载链接】prism

Turn any OpenAPI2/3 and Postman Collection file into an API server with mocking, transformations and validations.

项目地址:https://gitcode.com/gh_mirrors/pris/prism
点击查看免费下载

导读

@stoplight/prism-http-server是 Prism 的嵌入式 HTTP 服务器包,它允许开发者在 Node.js 代码中直接以编程方式创建 mock 服务:只要给定一份 OpenAPI 2/3 或 Postman Collection 文档,即可通过createServer()启动一个具备路由匹配、请求/响应校验、Mock 数据生成和 CORS 处理的真实 HTTP 服务。本文以packages/http-server/README.md为主干,结合该包与@stoplight/prism-http、@stoplight/prism-core的源码实现,讲解createServer的完整用法、全部配置项的含义与默认行为、逐请求级的响应覆盖机制,以及如何在测试套件中安全地启停服务。读完本文,你将能够在自己的测试或本地开发流程中,用不到 30 行代码搭建一个完全由 OpenAPI 文档驱动的 Mock API 服务器。

Prism Server 是什么:一个可嵌入的 HTTP 层

在 Prism 仓库中,@stoplight/prism-http-server(源码位于 packages/http-server)负责将@stoplight/prism-http的核心处理逻辑暴露为真实可监听的 HTTP 端口。它基于micri构建路由,同时从@stoplight/prism-http导入createInstance来组装完整的请求处理管线。整个包对外只暴露一个入口——createServer,见 packages/http-server/src/index.ts:

export { createServer } from './server';

它与 CLI 的关系是:prism mock、prism proxy命令在底层最终也是调用同一个createServer(见 packages/cli/src/util/createServer.ts 中对createHttpServer的引用)。因此,通过编程方式使用本包能获得与 CLI 完全一致的行为,同时拥有完全的控制权——这正是把它嵌入测试或定制工具的价值所在。

⚠️ 重要提示:该包的 API 目前仍处于实验阶段,官方 README 明确声明“当前 API 仍属实验性,可能随时变更,请自行承担使用风险”。

快速上手:最小可运行示例

README 给出的用法非常简洁,下面完整保留并补充必要说明:

const { createServer } = require('@stoplight/prism-http-server'); const { getHttpOperationsFromSpec } = require('@stoplight/prism-cli/dist/operations'); const { createLogger } = require('@stoplight/prism-core'); async function createPrismServer() { const operations = await getHttpOperationsFromSpec('YOUR-URL'); const server = createServer(operations, { components: { logger: createLogger('TestLogger'), }, cors: true, config: { checkSecurity: true, validateRequest: true, validateResponse: true, mock: { dynamic: false }, isProxy: false, errors: false, }, }); await server.listen(4010); return { close: server.close.bind(server), }; } const server = await createPrismServer(); server.close();

几个关键点需要展开说明:

  • getHttpOperationsFromSpec的参数'YOUR-URL'可以是本地文件路径、可 fetch 的远程 URL,或直接传入内存中的规范对象。从 packages/http/src/utils/operations.ts 的源码可以看到,它会自动识别文档类型:存在swagger字段按 OAS2 转换、存在openapi字段按 OAS3 转换、存在item数组且带info.name则按 Postman Collection 转换,否则抛出Unsupported document format。转换过程中还会对$ref进行 dereference 与 bundle,因此传入的 operations 已经是解析完毕、可直接用于路由和 Mock 的标准化结构。
  • createLogger来自@stoplight/prism-core,其实现基于 pino,并注册了一个额外的success自定义日志级别(见 packages/core/src/logger.ts)。
  • server.listen(4010)返回一个 Promise,resolve 的值为服务器实际监听地址字符串(形如http://127.0.0.1:4010),便于日志输出或动态拼接测试 URL。
  • server.close()会先调用closeAllConnections()再关闭服务,确保挂起的连接被妥善处理(见 packages/http-server/src/server.ts 中close方法的实现),适合在测试的afterAll阶段调用。

深入createServer的签名与返回值

createServer的类型定义位于 packages/http-server/src/types.ts:

export interface IPrismHttpServerOpts { components: PickRequired<Partial<PrismHttpComponents>, 'logger'>; config: IHttpConfig; cors: boolean; } export interface IPrismHttpServer { readonly prism: PrismHttpInstance; readonly logger: Logger; close: () => Promise<void>; listen: (port: number, address?: string, backlog?: number) => Promise<string>; }

参数与返回值逐项说明:

成员类型含义
components必须包含loggerPrism 的组件集合,其中logger是必填项,用于输出请求/校验日志
configIHttpConfig全局默认行为配置(详见下一节)
corsboolean是否启用 CORS 处理
prism(getter)PrismHttpInstance底层 Prism 实例,可拿到.request()直接编程调用
logger(getter)Logger服务器使用的 pino logger
listen(port, address?, backlog?)Promise<string>监听端口并返回地址字符串
close()Promise<void>关闭所有连接并停止服务

从 packages/http-server/src/server.ts 的实现可见,listen在底层对server.once('error')做了监听,端口被占用时 Promise 会以错误消息 reject;因此用它做测试时,需要留意不同测试套件并行运行时不要共用端口(官方测试注释也特别提醒了这一点,见 packages/http-server/src/tests/server.oas.spec.ts)。

配置项全解:config的每个字段

config的类型是IHttpConfig,它由基础配置IPrismBaseConfig(定义于 packages/core/src/types.ts)与mock子配置(IHttpOperationConfig,定义于 packages/http/src/types.ts)组合而成:

字段类型默认行为与作用
checkSecurityboolean是否执行安全方案校验(如 apiKey、basicAuth、bearer、digestAuth),对应validateSecurity组件
validateRequestboolean是否对请求体、请求头、查询参数、路径参数做校验,对应validateInput组件
validateResponseboolean是否校验生成的响应是否与规范声明的响应一致,对应validateOutput组件
errorsboolean校验失败时是否以 HTTP 错误(Problem+JSON)形式返回而不是仅记录日志;CLI 中对应--errors标志
isProxybooleanfalse表示纯 Mock 模式;true表示代理模式,此时还必须提供upstream: URL
upstreamProxystring \| undefined代理模式下转发请求时使用的上游代理地址
mock.dynamicbooleanfalse优先使用规范中的静态 example;true使用 json-schema-faker 基于 schema 动态生成
mock.codenumber(可选)强制 Mock 返回的响应状态码
mock.exampleKeystring(可选)强制使用指定名称的 example
mock.ignoreExamplesboolean(可选)忽略规范中的 example,静态模式下由 Prism 自行生成示例
mock.seedstring(可选)动态生成时使用的随机种子,使结果可复现

在核心工厂 packages/core/src/factory.ts 中,checkSecurity与validateRequest会被收集合并为输入校验结果;validateResponse则决定是否对 Mock/转发得到的输出再次校验。也就是说,这些开关直接决定了上面那条请求处理管线中哪些环节会真正执行。

mock.dynamic两种模式的差异

dynamic是使用频率最高的配置,值得单独说明。在 packages/http/src/mocker/index.ts 的createPayloadGenerator中可以看到:

return config.dynamic ? generate(resource, resource['__bundled__'], source, config.seed) : generateStatic(resource, source);
  • dynamic: false(静态模式):优先返回规范里写明的examples;没有 example 时,由 Prism 根据 schema 生成一个静态示例。
  • dynamic: true(动态模式):完全忽略 example,用 json-schema-faker 根据 schema 生成数据,同一接口每次调用结果通常不同;配合seed可得到确定性结果。

官方测试 packages/http-server/src/tests/server.oas.spec.ts 验证了这些行为:动态模式下连续两次请求返回不同对象;设置相同seed后两次请求返回严格相同对象;dynamic: true时即使ignoreExamples为真也会走动态生成。

请求处理管线:路由 → 校验 → Mock/转发 → 序列化

createServer内部把每个请求按以下管线处理(完整实现见 packages/http-server/src/server.ts,底层组装见 packages/http/src/index.ts):

  1. 解析请求体:根据Content-Type判断,JSON 走json()解析、其余走text()解析,上限均为 10MB;若Content-Length为 0 或两个长度头都缺失,则视为无 body,返回null。
  2. 构建标准输入:将 method、pathname、query(含多值参数)、headers、body 组装为IHttpRequest。
  3. 合并逐请求配置:调用getHttpConfigFromRequest解析请求级覆盖项,与全局config合并(mock子对象通过merge叠加)。
  4. 执行 Prism 管线:由工厂factory依次执行route→validateSecurity/validateInput→mock或forward→validateOutput。
  5. 发送响应:根据响应头content-type序列化 body,写回客户端;校验产生的违规项写入sl-violations响应头。

其中路由组件(packages/http/src/router/index.ts)会先按路径片段计算匹配得分、优先选择更具体的端点,再依次匹配 path、method、server;未匹配到路径返回 404(NO_PATH_MATCHED_ERROR)、匹配到路径但方法未定义返回 405(NO_METHOD_MATCHED_ERROR)。校验组件(packages/http/src/validator/index.ts)则负责 body、headers、query、path 及安全方案的规则比对。

请求级覆盖:Prefer头与__查询参数

这是 Prism Server 非常实用的特性:允许单个请求临时覆盖全局配置,而不影响服务本身。解析逻辑位于 packages/http-server/src/getHttpConfigFromRequest.ts:

  • Prefer头(优先):支持code=404、dynamic=true、seed=...、example=...四种偏好,例如Prefer: code=404, dynamic=false。
  • 查询参数(Prefer头缺失时的回退):__code、__dynamic、__seed、__example,以及用于指定 server 的__server。

解析时code必须是三位数字(否则报UNPROCESSABLE_ENTITY422 错误),dynamic必须是true/false。单测 packages/http-server/src/tests/getHttpConfigFromRequest.spec.ts 明确验证了“Prefer头优先于查询参数”的优先级规则。

典型用法示例:

# 强制返回 404 响应 curl http://localhost:4010/pets/123?__code=404 # 指定某个命名 example curl http://localhost:4010/pets/123?__example=cat # 用 Prefer 头动态生成 curl -H "Prefer: dynamic=true, seed=test_seed" http://localhost:4010/pets # 校验请求必须匹配的 server curl http://localhost:4010/pets/10?__server=https://petstore.swagger.io/v2

这些行为在 packages/http-server/src/tests/server.oas.spec.ts 中有系统性的端到端验证:__code=499但规范无此响应码且无 default 响应时返回 404 Problem+JSON;请求不存在的 example 同样返回 404;__server传入未在规范中声明的地址则返回 404 并附带NO_SERVER_MATCHED_ERROR的详细错误信息。

CORS 与错误响应格式

当cors: true时,服务器会自动处理 OPTIONS 预检请求:回写Access-Control-Allow-Origin(默认回显请求的origin,否则*)、Access-Control-Allow-Headers、Access-Control-Allow-Credentials: true、Access-Control-Expose-Headers,预检请求返回 204,并设置Vary: origin与Content-Length: 0(后者是为规避 Safari 对 204 的兼容问题)。非预检请求也会统一附加这些头。实现见 packages/http-server/src/server.ts 的setCommonCORSHeaders。

错误响应统一使用 RFC 7807 风格的 Problem+JSON,包含type、title、status、detail四个字段,由ProblemJsonError(定义于 packages/http/src/types.ts)生成。校验失败时还会在响应头写入sl-violations,内容为序列化后的违规明细 JSON(location/severity/code/message),超过约 8KB 上限时会被截断并加上Too many violations!前缀。

响应序列化规则

createServer发送响应前会调用 packages/http-server/src/serialize.ts 按Content-Type选择序列化器:

  • application/json/application/*+json:JSON.stringify;
  • application/xml/application/*+xml:使用fast-xml-parser的XMLBuilder构建 XML;
  • text/*:字符串原样返回;若试图把复杂对象序列化为文本,则抛出 500 错误(NO_COMPLEX_OBJECT_TEXT);
  • 未匹配的 Content-Type:字符串直接返回,否则报“找不到序列化器”错误。

这解释了为什么Accept: application/xml的请求可以拿到 XML 形态的 Mock 响应,而纯文本接口的响应体会保持字符串形式。

在测试中管理生命周期:监听与关闭

把 Prism Server 用于测试时,官方测试(packages/http-server/src/tests/server.oas.spec.ts)给出了一套值得参考的模式:

const address = await server.listen(30001, '127.0.0.1'); // 之后用 node-fetch 基于 address 拼接 URL 发起断言 afterAll(() => server.close());

几点实践建议:

  • 用server.close.bind(server)传给afterAll/afterEach,避免this指向问题(README 示例即采用该写法)。
  • 不同测试套件并行运行时会共享进程,端口必须互不相同,否则listen会 reject。
  • listen支持第二个参数address,测试中显式绑定127.0.0.1更稳妥。

匿名安装统计(Anonymized analytics)与关闭方式

@stoplight/prism-http-server在安装时通过 Scarf 收集匿名安装统计,用于帮助维护者了解库的使用情况。注意:统计仅在npm install安装过程中运行,不会在服务运行时上报。官方 README 提供了两种关闭方式,此处原样继承:

  1. 在项目的package.json中设置:
{ // ... "scarfSettings": { "enabled": false } // ... }
  1. 或在执行安装时设置环境变量:
SCARF_ANALYTICS=false npm install

与 CLI 的对应关系

如果你已经熟悉prism mock命令,可以快速建立映射:CLI 在 packages/cli/src/commands/mock.ts 中暴露的--dynamic/-d、--seed、--ignoreExamples、--errors、--cors、--port、--host等选项,最终都会落入createServer的config与cors参数(见 packages/cli/src/util/createServer.ts 中shared对象的组装逻辑)。也就是说,编程方式与 CLI 是同一套引擎,本文讲解的每个配置字段都能在 CLI 文档中找到对应物。

环境要求与注意事项

  • 当前仓库版本为5.16.0,packages/http-server/package.json 声明要求Node.js >= 24.19.0,请确认运行环境满足要求。
  • 包导出入口为dist/index.js,类型定义在dist/index.d.ts,需先构建(仓库根目录npm run build)或使用发布版本。
  • API 仍属实验性,升级大版本时建议关注 CHANGELOG(packages/http-server/CHANGELOG.md)中的破坏性变更说明。
  • getHttpOperationsFromSpec对输入文档会发起远程$ref解析,请求头带上了User-Agent: PrismMockServer/<version>;如果规范引用了需要鉴权的远程资源,需要提前处理好可访问性。

小结

@stoplight/prism-http-server把 Prism 的完整能力封装成一个可编程的 HTTP 服务:getHttpOperationsFromSpec负责把任意 OAS2/3 或 Postman Collection 文档解析为标准操作集合,createServer负责路由、校验、Mock、序列化与 CORS,Prefer头与__查询参数负责逐请求级的精细控制。理解其配置项与底层管线(route → validate → mock/forward → serialize)之后,无论是单测中的内联 Mock、契约测试,还是本地开发服务器,你都可以用同一套代码以编程方式快速落地。

  • 后端
  • 接口测试
  • 开发工具

【免费下载链接】prism

Turn any OpenAPI2/3 and Postman Collection file into an API server with mocking, transformations and validations.

项目地址:https://gitcode.com/gh_mirrors/pris/prism
点击查看免费下载
上一篇:Refine v5 MUI CloneButton 组件完全指南:从 CRUD 克隆操作到源码级原理
下一篇:LeetCode-Go 题解 145:Binary Tree Postorder Traversal 二叉树后序遍历的递归与迭代实现

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询