一、在 BFF 层重塑小微风控体验
在开发面向银行客户经理或信审员的“小微企业进件系统”时,前端页面通常需要展示一个综合看板:左边是企业经营状况,中间是法人借贷评分,右边是司法诉讼风险。
如果前端直接调用底层数据接口,将面临两个问题:
- 数据过载:天远API 的“全能小微企业报告”一次性返回数千个字段,直接透传会消耗大量带宽。
- 逻辑泄露:加密密钥和敏感的风控规则(如“命中黑名单即拒单”)不应暴露在浏览器端。
通过 Node.js 构建 BFF 层,我们可以充当“数据适配器”的角色:向上对接天远API(COMBQN13),向下为前端提供精简、脱敏后的 JSON 数据。本文将演示如何利用 Node.js 的 crypto 模块处理 AES 加密,并编写高效的 Transformer(转换器)将异构的子产品数据整合成统一的视图。
二、API接口调用示例(Node.js版)
1. 接口技术规范
- 接口地址:
https://api.tianyuanapi.com/api/v1/COMBQN13 - HTTP 方法:POST
- 鉴权:Header (
Access-Id) + Body (data密文) - 聚合特性:响应体是一个
responses数组,每个元素包含api_code(子产品码)和data。
2. Node.js 完整实现代码
本示例包含 AES 加解密工具,以及一个核心的 DashboardPresenter 类,用于将复杂的聚合数据转换为前端看板所需的结构。
JavaScript
const axios = require('axios');
const crypto = require('crypto');
// 配置信息
const CONFIG = {
apiUrl: '<https://api.tianyuanapi.com/api/v1/COMBQN13>',
accessId: 'YOUR_ACCESS_ID',
accessKey: 'YOUR_ACCESS_KEY_HEX' // 16字节 Hex 字符串
};
class SmeReportBFF {
constructor() {
this.key = Buffer.from(CONFIG.accessKey, 'utf-8').slice(0, 16);
this.algorithm = 'aes-128-cbc';
}
// --- AES 加密 (AES-128-CBC + PKCS7) ---
encrypt(dataObj) {
try {
const iv = crypto.randomBytes(16);
const plaintext = JSON.stringify(dataObj);
const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'base64');
encrypted += cipher.final('base64');
// 拼接 IV + 密文 -> Base64
const ivBuffer = iv;
const encryptedBuffer = Buffer.from(encrypted, 'base64');
const combinedBuffer = Buffer.concat([ivBuffer, encryptedBuffer]);
return combinedBuffer.toString('base64');
} catch (err) {
console.error('Encrypt Error:', err.message);
return null;
}
}
// --- 核心:数据清洗 Transformer ---
// 将异构的 responses 数组转换为前端 Dashboard 需要的扁平对象
transformToDashboard(apiResponse) {
const dashboard = {
company: { name: '未查得', status: '未知', risk: 'low' },
person: { score: 0, overdueAmount: 0, loanCount: 0 },
legal: { lawsuitCount: 0, totalAmount: 0 },
blacklist: { isHit: false, details: [] }
};
const responses = apiResponse.responses || [];
responses.forEach(item => {
if (!item.success || !item.data) return;
const data = item.data;
switch (item.api_code) {
case 'QYGL3F8E': // 人企关系 -> 提取企业基本面
if (data.items && data.items.length > 0) {
const info = data.items[0].basicInfo || {};
dashboard.company.name = info.name;
dashboard.company.status = info.regStatus;
// 简单规则:注销或吊销视为高风险
if (['注销', '吊销'].includes(info.regStatus)) {
dashboard.company.risk = 'high';
}
}
break;
case 'JRZQ7F1A': // 全景雷达 -> 提取法人借贷画像
const behavior = data.behavior_report_detail || {};
dashboard.person.score = parseInt(behavior.B22170001 || 0); // 借贷行为分
dashboard.person.overdueAmount = behavior.B22170031 || "0"; // 近6月逾期金额
dashboard.person.loanCount = parseInt(behavior.B22170005 || 0); // 近12月贷款笔数
break;
case 'JRZQ8A2D': // 特殊名单 -> 黑名单检测
if (data.id && data.id.court_bad === '0') { // 0表示命中
dashboard.blacklist.isHit = true;
dashboard.blacklist.details.push('法院失信人');
}
if (data.cell && data.cell.nbank_lost === '0') {
dashboard.blacklist.isHit = true;
dashboard.blacklist.details.push('网贷高风险');
}
break;
case 'FLXG7E8F': // 司法涉诉 -> 涉诉统计
const stats = data.judicial_data?.lawsuitStat?.count || {};
dashboard.legal.lawsuitCount = stats.count_total || 0;
dashboard.legal.totalAmount = stats.money_total || 0;
break;
}
});
return dashboard;
}
// --- 业务调用流程 ---
async getSmeRiskProfile(params) {
const payload = {
...params,
authorized: "1" // 补充必填字段
};
const encryptedData = this.encrypt(payload);
if (!encryptedData) return;
try {
const url = `${CONFIG.apiUrl}?t=${Date.now()}`;
const res = await axios.post(url, { data: encryptedData }, {
headers: {
'Content-Type': 'application/json',
'Access-Id': CONFIG.accessId
}
});
// 假设外层未加密,直接处理 responses
if (res.data && res.data.responses) {
console.log('API 调用成功,正在生成 Dashboard 数据...');
return this.transformToDashboard(res.data);
} else {
console.error('API 响应异常:', res.data);
return null;
}
} catch (error) {
console.error('网络请求失败:', error.message);
return null;
}
}
}
// === 使用示例 ===
(async () => {
const bff = new SmeReportBFF();
// 模拟前端发来的请求
const dashboardData = await bff.getSmeRiskProfile({
name: "张三",
id_card: "110101199001011234",
mobile_no: "13800138000"
});
if (dashboardData) {
console.log("=== 前端看板数据 (JSON) ===");
console.log(JSON.stringify(dashboardData, null, 2));
// 简单的逻辑判断
if (dashboardData.blacklist.isHit) {
console.warn(">> 触发前端弹窗:该客户命中黑名单,禁止进件!");
}
}
})();
三、核心数据结构解析
Node.js 处理此接口的优势在于能够轻松操作 JSON 对象。我们需要关注如何将数组形式的响应映射为语义化的对象。
1. 原始聚合响应
JavaScript
// 这是一个数组,查找特定数据需要遍历
responses: [
{ api_code: "QYGL3F8E", data: { ... } },
{ api_code: "JRZQ7F1A", data: { ... } }
]
2. 清洗后的 Dashboard 数据
经过 transformToDashboard 函数处理后,数据结构变得极其精简,完全适配前端 UI 组件的 props:
JavaScript
{
"company": {
"name": "某某科技公司",
"status": "存续",
"risk": "low"
},
"person": {
"score": 650, // 借贷分
"overdueAmount": "[5000,10000)" // 逾期金额
},
"blacklist": {
"isHit": true, // 是否命中黑名单
"details": ["法院失信人"]
}
}
四、字段详解(BFF层 透传策略)
以下字段是在 BFF 层进行数据清洗时,最常被提取并透传给前端的关键指标。
1. 身份与经营核验 (Identity & Biz)
| 原始字段 (Path) | 目标字段 (UI) | 处理逻辑 |
|---|---|---|
QYGL3F8E...basicInfo.name | companyName | 展示用。 |
QYGL3F8E...basicInfo.regStatus | bizStatus | 用于前端标签颜色(存续=绿,注销=红)。 |
QYGL3F8E...basicInfo.estiblishTime | bizAge | 计算得出“经营年限”(如 3.5年)。 |
2. 借贷与偿债能力 (Credit & Ability)
| 原始字段 (Code) | 目标字段 (UI) | 说明 |
|---|---|---|
| B22170001 | creditScore | 贷款行为分 (1-1000)。可以直接用于绘制仪表盘图表。 |
| B22170031 | recentOverdue | 近6个月逾期金额。若非 "0",前端高亮显示。 |
| A22160003 | multiHeadCount | 申请命中机构数。用于展示“多头借贷”程度。 |
3. 风险阻断 (Blocking Risk)
| 原始字段 (Key) | 目标字段 (UI) | 逻辑 |
|---|---|---|
id_court_bad | isDishonest | (JRZQ8A2D) 法院失信。红线指标。 |
count_wei_total | lawsuitPending | (FLXG7E8F) 未结案数量。数量过多提示风险。 |
五、应用价值分析
在 Node.js 中间件层集成天远全能小微企业报告,主要解决以下业务痛点:
-
数据脱敏与安全 (Security):
原始接口返回了企业主详细的借贷记录(如具体金额区间)。BFF 层可以将其转换为模糊的等级(如“高/中/低”),避免敏感数据直接暴露在浏览器网络请求中。
-
前端性能优化 (Performance):
原始响应体可能高达 100KB+。经过 Transformer 清洗后,传输给前端的 JSON 通常小于 2KB,显著提升了移动端 H5 进件页面的加载速度。
-
统一错误处理 (Error Handling):
聚合接口中的某个子产品可能会失败(success: false)。Node.js 可以优雅地处理这种情况,例如:如果“司法涉诉”查询超时,BFF 层可以返回默认的“查询中”状态,而不影响“黑名单”和“企业信息”的正常展示,保证用户体验的降级而非崩溃。
六、总结
天远全能小微企业报告 API 是 SME(小微企业) 风控场景下的数据核武器。
对于 Node.js 开发者,核心任务是构建一个健壮的 Aggregation & Transformation 层。通过本文示例的 DashboardPresenter 模式,您可以轻松地将复杂的后台数据“翻译”为前端易读的业务语言,打造流畅、安全的小微企业信贷申请体验。