jamerly-apigateway-sdk
v0.1.0
Published
JavaScript/TypeScript SDK for the Jamerly API Gateway: X-Biz-Id routing, AES-256-CBC payload encryption and the unified response envelope.
Readme
jamerly-apigateway-sdk
对接 api-gateway 的 JavaScript / TypeScript SDK。零运行时依赖,浏览器与 Node 通用。
把三件所有接入方都要重写一遍的事收进一个包:
X-Biz-Id路由 —— 网关据此找路由表和该业务的aes_key;- AES-256-CBC 载荷加解密 —— 请求体加密、响应
data解密,格式与网关services/proxy_service.py的_encrypt_data/_decrypt_data逐字节一致; - 统一信封拆封 ——
{success, errorLevel, message, code, data}拆成业务数据, 出错统一抛GatewayError。
安装
npm i jamerly-apigateway-sdk快速开始
import { createGatewayClient } from 'jamerly-apigateway-sdk';
const gw = createGatewayClient({
baseUrl: 'https://api.jamerly.dev',
bizId: 'yogii',
aesKey: 'imwfV59qm', // 网关后台里该业务的 aes_key;不填则不加密
getToken: () => localStorage.getItem('token'),
skipAuth: (ctx) => ctx.path.startsWith('/member/login'),
});
const status = await gw.get('/member/status');
const order = await gw.post('/member/orders', { storeId: 3, lines: [...] });get/post/put/patch/delete 返回的就是解密并拆掉信封之后的上游响应体
(对 yogii 后端就是 { code, message, data }),不需要再 .data.data。
协议对应关系
| 协议要求 | SDK 行为 |
|---|---|
| X-Biz-Id 头 | 每个请求自动带上 |
| 请求体加密 | POST/PUT/PATCH/DELETE 的 JSON 体自动加密;GET 的 query 不加密(网关也不解) |
| 响应 data 解密 | 配了 aesKey 且 data 是字符串时自动解 |
| success: false | 抛 GatewayError,level 取自 errorLevel(internal / remote) |
| 失败体里的 data / details 也可能是密文 | 尽力解开后放进 error.details |
| 上游非 2xx 但 success: true | 仍然抛错(网关把上游状态码填在 HTTP status 上),level: 'remote' |
| text/event-stream 原样透传 | 用 fetchRaw() 拿原始 Response |
FormData / Blob / ArrayBuffer / 字符串体一律原样发送,不加密(与网关的
multipart 分支一致),且不会强行设 Content-Type。
错误处理
所有失败都抛 GatewayError,字段与旧 axios 拦截器时代对齐(code / message / details):
import { isGatewayError } from 'jamerly-apigateway-sdk';
try {
await gw.post('/member/recharge', { amount: 0 });
} catch (err) {
if (isGatewayError(err)) {
err.level; // 'client' | 'network' | 'timeout' | 'internal' | 'remote' | 'business'
err.code; // 业务码或 HTTP 码
err.status; // HTTP 状态码
err.details; // 解密后的错误体
}
}level 的含义:
client—— SDK / 调用方问题:加密失败、主动 abort、配置缺失;network—— 压根没连上网关(断网 / DNS / CORS);timeout—— 超过timeout被掐断;internal—— 网关自己拒绝:路由未命中、鉴权不过、解密失败;remote—— 上游服务返回错误;business—— 上游 HTTP 200,但响应体里的code不是成功码(默认[0, 200])。
业务码检查可以用 successCodes 改,或 ignoreBusinessCode: true 关掉。
钩子
宿主自己的会话、埋点、"系统维护中"提示挂在钩子上,SDK 不碰这些:
createGatewayClient({
// ...
hooks: {
onRequest: (ctx) => { ctx.headers['X-Trace-Id'] = traceId(); },
onResponse: (ctx) => console.debug(ctx.request.url, ctx.data),
onUnauthorized: () => store.logout(), // HTTP 401 或业务码 401
onAvailability: (ok) => store.setSystemUnavailable(!ok), // 网络错误 / 超时 / 502 / 504
onError: (err) => report(err),
},
});运行环境
- 浏览器:需要安全上下文(https 或 localhost),否则没有
crypto.subtle; - Node 19+:开箱可用;
- Node 18:
crypto全局是实验性的,显式注入:
import { webcrypto } from 'node:crypto';
createGatewayClient({ /* ... */ crypto: webcrypto });fetch 同理可以用 fetch 选项替换(打桩、代理、自定义 agent)。
独立使用加解密
不走客户端也能单独用这两个函数(比如在 Node 脚本里手工造请求):
import { encryptPayload, decryptPayload } from 'jamerly-apigateway-sdk';
const cipherText = await encryptPayload({ a: 1 }, aesKey);
const plain = await decryptPayload(cipherText, aesKey);开发与发布
npm run build # 出 dist/esm + dist/cjs + d.ts
npm test # node:test,含与网关 Python 实现对齐的线上格式用例
npm publish # prepublishOnly 会先跑一遍 build + test发的是公共 npmjs,不是内网 Nexus —— 别改回去。nexus.jamerly.dev 解析到
10.33.1.2,官网 prod 是把源码同步到 gitlab.com 由 Cloudflare 构建,那台机器
在公网上,拉不到内网制品库。
包名不带 scope 也是这个原因链上的:apigateway-sdk 在 npmjs 上早被一个 AWS
相关的旧包占了,而带 scope 的 @jamerly/* 要先在 npm 上建 org,所以退到
jamerly-apigateway-sdk。
包里不含任何密钥:aes_key 属于接入方配置,写在各自应用里(官网是纯前端 SPA,
那个 key 本来在浏览器里就能扒到,公开这个包不增加泄露面)。
test/wire-format.test.mjs 里的两条用例锁死了与 api-gateway 的字节级互通:
一条解网关 Python 侧产出的密文,一条在固定 IV 下比对逐字节相同的密文。
这两条挂了说明协议变了,不要改测试去迁就。
