@equinor/ inform-framework-vite-plugin-api-service (英语)
用于代理服务发现请求的 Vite 插件, 在 Fusion 中添加服务器拥有的路由 框架应用开发.
[TIP] 应用程序服务模拟器属于可执行文件
mocks/<service>.mock.ts模块创建defineService见 模拟服务指南。使用此软件包 路由 API 只有在建设开发基础设施或自定义 Vite 集成时直接使用.
需要时使用此插件 :
- 与服务发现相结合 ——代理请求一个远程发现端点并重新映射服务URL到dev-server可以管理的本地路线.
- 添加服务器自主响应 ——定义健康检查,召回或自定义主机行为的中间软件路径.
- 拦截和改变对策 ——在到达客户端前修改代理响应有效载荷(规范数据,注入元数据等).
该插件是为Fusion Framew Dev Server生态系统而设计的,但在任何Vite项目中工作.
安装
pnpm add -D @equinor/fusion-framework-vite-plugin-api-service
快速启动
// vite.config.ts
import { defineConfig } from 'vite';
import apiServicePlugin, { createProxyHandler } from '@equinor/fusion-framework-vite-plugin-api-service';
export default defineConfig({
plugins: [
apiServicePlugin({
proxyHandler: createProxyHandler(
'https://discovery.example.com/services',
(services, { route }) => {
const routes = services.map((svc) => ({
match: `/${svc.name}/*path`,
proxy: {
target: svc.url,
rewrite: (p: string) => p.replace(`/${svc.name}`, ''),
},
}));
return {
data: services.map((svc) => ({ ...svc, uri: `${route}/${svc.name}` })),
routes,
};
},
),
}),
],
});
如何运作
服务发现流程
flowchart TD
subgraph "Service Discovery Flow"
SD1[Client] -->|Request /@fusion-services| SD2[Plugin]
SD2 -->|Proxy request| SD3[Service Discovery Endpoint]
SD3 -->|Return service data| SD2
SD2 -->|Transform & remap services| SD4[Modified Service List]
SD4 -->|Return to client| SD1
end
- 客户端请求服务列表(例如.
/@fusion-services) (中文(简体) ). - 插件将请求代理到真实的服务发现端点.
- 这个
generateRoutes回调将每个服务 URL 映射到本地代理路径并注册路径 . - 修改后的服务列表被退回客户端.
代理响应 (上游):
[{ "id": "abc", "name": "apps", "url": "https://apps.prod.example.com/" }]
插件响应 (致客户端):
[{ "id": "abc", "name": "apps", "url": "/@fusion-api/apps" }]
普通 API 请求流程
flowchart TD
subgraph "API Request Flow"
API1[Client] -->|Request /@fusion-api/apps/all| API2[Plugin]
API2 -->|Proxy request| API3[Real API Service]
API3 -->|Response| API2
API2 -->|Apply interceptors| API4[Processed Response]
API4 -->|Return to client| API1
end
- 客户端通过代理URL(如.
/@fusion-api/apps/all) (中文(简体) ). - 插件解决匹配的路由并代理请求到上游 URL.
- 可选反应拦截器改变有效载荷.
- 结果归客户端.
移动路线流
flowchart TD
subgraph "Mock Route Flow"
M1[Client] -->|Request| M2[Plugin]
M2 -->|Check routes| M3{Mock exists?}
M3 -->|Yes| M4[Return Mock Response]
M3 -->|No| M5[Continue to Proxy / Next]
M4 --> M1
end
- 客户端会提出匹配中间软件路径的请求.
- 插件直接执行中间软件处理器,不代理.
- 如果没有中间软件路由匹配,则请求会通过代理路由或下一个中间软件.
配置
插件选项
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
route | string | '/@fusion-api' | 安装插件中间软件的基础路径 . |
process | ProcessRouteOptions | —— 说 | 额外的路由处理选项(例如. onProxyRes 师曰. |
logger | PluginLogger | —— 说 | 调试/info/warn/error消息的锁定器 。 过 console 快速调试. |
headers | Record<string, string> | —— 说 | 标题添加到每一个代理的上游请求(服务发现和代理路线)中,例如用于识别dev-server流量. 一条路是自己的 proxy.headers 优先发言. |
服务发现 createProxyHandler
createProxyHandler 创建一个 ApiProxyHandler 并动态生成来自响应的代理路径.
import { createProxyHandler } from '@equinor/fusion-framework-vite-plugin-api-service';
const proxyHandler = createProxyHandler(
// URL of the upstream service discovery endpoint
'https://api.example.com/service-discovery',
// Callback that processes the response and returns routes
(responseData, { route, request }) => {
const routes = responseData.services.map((service) => ({
match: `/${service.name}/*path`,
proxy: {
target: service.url,
rewrite: (path: string) => path.replace(`/${service.name}`, ''),
},
}));
return {
data: responseData,
routes,
};
},
// Optional configuration
{
route: '/@fusion-services', // where discovery proxy is mounted (default)
apiRoute: '/@fusion-api', // base path for generated routes (default)
proxyOptions: { changeOrigin: true, secure: false },
logger: console,
},
);
apiServicePlugin({ proxyHandler });
响应缓存
createProxyHandler 缓存服务在内存中的发现响应, 因此一个浏览器标签卡被卡入了重载回路( Vite full reload, auth direct, crashing app) 无法淹没上游的发现 API :
- 成功反应被重新用于 60秒钟。原始的上游有效载荷被缓存,并在每次请求时通过您的处理器传递,因此依赖请求输出(例如,从源代码中创建的URI)
referer保持正确的状态. - 答复失败(状况)
>= 400) 以相同的状态代码回答 10 秒钟 而不呼叫上游. - 条目由 URL 和 散列 键入
Authorization信头,所以一个新符号从未收到一个缓存到另一个的响应. 仅GET请求被缓存 . - 缓存反应
x-fusion-discovery-cache: hit头曰.
锁上护身符
模拟认证问题未签名的令牌( Q)alg: none),真实的服务总是拒绝. 插件从不向公共主机转发携带这种标志的请求——无论是通过服务发现代理还是代理路线. 它会回答的 401 本地为 x-fusion-dev-server-blocked: mock-token 换句话说.
本地目标仍然被允许,因此模拟服务器和当地API继续工作: localhost, (中文(简体) ), *.localhost,单标签主机,如 Docker 编译服务(http://api:8080, (中文(简体) ), *.local, (中文(简体) ), *.internal范围.
添加服务器拥有的路由
定义开发主机拥有的端点的中间软件路径,例如健康检查和 基础设施召回:
[大 Fusion 应用程序服务模拟器应该使用可执行文件
mocks/<service>.mock.ts模块defineService,而不是手写 API-plugin 路线。 见 模拟服务指南。当 端点不是一个可以发现的服务模拟.
apiServicePlugin({
routes: [
{
match: '/health',
middleware: (_req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok' }));
},
},
{
match: '/users/:userId',
middleware: (req, res) => {
const userId = req.params?.userId;
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: userId, name: 'Test User' }));
},
},
],
});
合并代理路由和自定义路由
两者都可以供应 proxyHandler 财务报告和审定财务报表 routes。自定义路径在代理之前进行评估
服务:
apiServicePlugin({
proxyHandler,
routes: [
{
match: '/apps/my-local-app',
middleware: (_req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ appKey: 'my-local-app', version: 'dev' }));
},
},
],
});
路线匹配 createRouteMatcher
createRouteMatcher 创建匹配器函数,以对照模式测试 URL 路径并提取路径参数。 建造在 路径到备忘。 。 。 .
路径参数
import { createRouteMatcher } from '@equinor/fusion-framework-vite-plugin-api-service';
const matcher = createRouteMatcher({ match: '/api/users/:userId/profile' });
matcher('/api/users/123/profile', req); // { params: { userId: '123' } }
matcher('/api/posts/123', req); // false
通关卡
const serviceMatcher = createRouteMatcher({ match: '/api/services/:serviceName/*path' });
serviceMatcher('/api/services/auth/v1/token', req);
// { params: { serviceName: 'auth', path: [ 'v1', 'token' ] } }
多种图案
通过一系列图案来匹配其中的任何一种 :
const multiMatcher = createRouteMatcher({
match: ['/api/v1/users/:id', '/api/v2/users/:id'],
middleware: handler,
});
自定义匹配函数
对于高级逻辑,提供函数而不是字符串模式:
const customMatcher = createRouteMatcher({
match: (path, req) => {
if (path.startsWith('/api/custom') && req.method === 'GET') {
return { params: { custom: path.substring(12) } };
}
return false;
},
middleware: handler,
});
见 路径到记录的文档 用于完整的模式语法.
迁移:路径到regexp v9
此主要发行更改字符串模式匹配 createRouteMatcher,包括代理和
中间软件路线。 在同一段和处理器中有两个或两个以上参数的审查路线
在提升之前使用它们捕获的值.
const matcher = createRouteMatcher({
match: '/:file.:ext',
proxy: { target: 'http://localhost:3001' },
});
matcher('/foo.json.html', req);
// Before (v8): params = { file: 'foo.json', ext: 'html' }
// Now (v9): params = { file: 'foo', ext: 'json.html' }
扩展检查, 如 params.ext === 'html' 不再识别此 URL。 优先分开
当每个抓取有明确的含义时, 将路径及其调用者一起更新 :
const matcher = createRouteMatcher({
match: '/files/:file/extensions/:ext',
proxy: { target: 'http://localhost:3001' },
});
matcher('/files/foo.json/extensions/html', req);
// params = { file: 'foo.json', ext: 'html' }
如果 URL 无法更改, 请提供 自定义匹配函数 执行
您想要的解析和解码规则; v9 不恢复 v8 模糊的捕捉行为
自动。 参数分出部分的普通图案,例如 /users/:id进行
没有这种模糊性.
明确斜线终止模式,例如 /files/ 现在匹配 /files/ 但没有 /files//。 。 。 .
将呼叫者规范到一个尾巴上 一种没有明显斜线的图案,例如 /files, (中文(简体) ),
还接受 /files/ 在匹配者的默认选项下.
添加被点值的路由回归,被捕获参数,并跟踪斜线. 检查代理
重写和中间软件的决定以及路由是否匹配. 依赖性仅为无害环境管理
,需要节点22或更新;此软件包使用其命名的 match 输出.
拦截器 createResponseInterceptor
createResponseInterceptor 截取了JSON代理响应,并在他们到达客户端之前进行改造. 非JSON回复和出错回复(status QQ 400)通过未受触动,带有其原始状态代码和头.
import { createResponseInterceptor } from '@equinor/fusion-framework-vite-plugin-api-service';
const interceptor = createResponseInterceptor(
(data) => ({
...data,
timestamp: new Date().toISOString(),
}),
{ logger: console },
);
类型安全转换
interface OriginalResponse {
items: string[];
totalCount: number;
}
interface TransformedResponse {
data: string[];
metadata: { count: number; timestamp: string };
}
const typedInterceptor = createResponseInterceptor<OriginalResponse, TransformedResponse>(
(response) => ({
data: response.items,
metadata: {
count: response.totalCount,
timestamp: new Date().toISOString(),
},
}),
);
说明: 拦截器要求
selfHandleResponse: true在代理配置上。 使用时自动设置createProxyHandler。 。 。 .
API 参考
出口
| 导出 | 说明 |
|---|---|
plugin (默认) | Vite 插件厂- 通过 PluginArguments 和可选 PluginOptions。 。 。 . |
createProxyHandler | 创建一个 ApiProxyHandler 服务发现代理. |
createRouteMatcher | 从路由定义创建路径匹配器. |
createResponseInterceptor | 为 JSON 转换创建代理响应截取器. |
DEFAULT_VALUES | 带有默认路由路径的 Enum (API_PATH, (中文(简体) ), SERVICES_PATH) (中文(简体) ). |
类型
| 类型 | 说明 |
|---|---|
PluginArguments | 插件厂的参数( R)routes, (中文(简体) ), proxyHandler) (中文(简体) ). |
PluginOptions | 可选插件配置( N)route, (中文(简体) ), process, (中文(简体) ), logger) (中文(简体) ). |
ApiProxyHandler | 代理处理器接口返回 createProxyHandler; 可选 middleware 成员在Vite 代理服务器之前应答请求 . |
ApiDataProcessor | 回调类型,用于处理服务发现回复. |
ApiRoute | 联盟 MiddlewareRoute 财务报告和审定财务报表 ProxyRoute。 。 。 . |
MiddlewareRoute | 带有自定义中件处理器的路由定义 . |
ProxyRoute | 路由定义可以代表远程目标. |
ApiRouteProxyOptions | 代理配置选项 ProxyRoute。 。 。 . |
Matcher | 路由匹配的函数类型 . |
MatchResult | 返回类型 a Matcher —— 说 boolean 或者说 { params }。 。 。 . |
PluginLogger | 子集数 Console 用于插件日志. |
JsonData | JSON-可序列价值类型联盟. |