一、在 BFF 层拦截多头借贷风险
在现代金融科技架构中,Node.js 常驻于业务网关层,负责聚合数据并为前端提供响应。当用户在 APP 端发起借款申请时,网关层需要在毫秒级时间内判断用户的风险等级,从而决定是直接拒绝、弹窗警告还是进入人工审核。
天远API 的"多头借贷行业风险版",提供了区别于传统征信的精细化行为画像 。它不仅能区分用户是在"银行"还是"P2P"平台借贷,还能识别出用户是否在"凌晨"进行高频申请。然而,该接口返回的 List<KV> 格式数据(如 [{"riskCode": "41001", "riskCodeValue": "50"}])对前端展示并不友好。
本文将演示如何在 Node.js 环境中,利用原生 crypto 模块实现高安全的 AES-128-CBC 通信,并编写高效的数据转换(Transformer)函数,将天远API的原始数据清洗为业务友好的结构化 JSON。
二、API接口调用示例(Node.js版)
1. 接口技术规范
- 接口地址 :
https://api.tianyuanapi.com/api/v1/DWBG7F3A - HTTP方法:POST
- 鉴权 :Header 需携带
Access-Id。 - Payload :Body 中的
data字段为 AES 加密并 Base64 编码后的字符串 1。
2. Node.js 完整实现代码
在 Node.js 中,我们使用 axios 发起请求,使用 crypto 处理加解密。特别注意:加密后的密文需要与 IV(初始化向量)拼接后再进行 Base64 编码。
JavaScript
javascript
const axios = require('axios');
const crypto = require('crypto');
// 配置信息
const CONFIG = {
apiUrl: '<https://api.tianyuanapi.com/api/v1/DWBG7F3A>',
accessId: 'YOUR_ACCESS_ID',
accessKey: 'YOUR_ACCESS_KEY_HEX' // 16字节HEX字符串
};
class IndustryRiskService {
constructor() {
// 确保 Key 为 Buffer
this.key = Buffer.from(CONFIG.accessKey, 'utf-8').slice(0, 16);
this.algorithm = 'aes-128-cbc';
}
// --- AES 加密 ---
encrypt(dataObj) {
try {
const iv = crypto.randomBytes(16); // 随机生成IV
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;
}
}
// --- AES 解密 ---
decrypt(base64Str) {
try {
const combinedBuffer = Buffer.from(base64Str, 'base64');
const iv = combinedBuffer.slice(0, 16); // 提取前16字节 IV
const content = combinedBuffer.slice(16); // 提取剩余密文
const decipher = crypto.createDecipheriv(this.algorithm, this.key, iv);
let decrypted = decipher.update(content, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return JSON.parse(decrypted);
} catch (err) {
console.error('Decrypt Error:', err.message);
return null;
}
}
// --- 数据清洗 Transformer ---
// 将数组 [{"riskCode": "41001", "riskCodeValue": "50"}] 转换为对象 {"41001": 50}
transformReport(rawData) {
const reportList = rawData['riskInfo_report_v3.1'] || [];
return reportList.reduce((acc, item) => {
acc[item.riskCode] = Number(item.riskCodeValue); // 转为数字方便计算
return acc;
}, {});
}
// --- 业务调用主流程 ---
async queryRisk(userParams) {
const encryptedData = this.encrypt(userParams);
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
}
});
if (res.data.code === 0) {
console.log('API调用成功,解析数据...');
const rawResult = this.decrypt(res.data.data);
// 执行数据清洗
const cleanData = this.transformReport(rawResult);
this.analyzeRisk(cleanData);
} else {
console.error('API业务错误:', res.data.message);
}
} catch (error) {
console.error('网络请求失败:', error.message);
}
}
// --- 简单的风控逻辑 ---
analyzeRisk(data) {
console.log('--- 用户风险画像 ---');
console.log(`多头借贷通用分 (41001): ${data['41001']}`);
console.log(`银行系借贷分 (41005): ${data['41005']}`);
console.log(`互金系借贷分 (41004): ${data['41004']}`);
// 示例规则:如果是深夜申请且互金分高
if (data['40105'] > 0 && data['41004'] > 60) {
console.warn('【高危预警】检测到"深夜高频借贷"行为,建议拦截!');
}
}
}
// 运行示例
const service = new IndustryRiskService();
service.queryRisk({
name: "王五",
id_card: "310101199001011234",
mobile_no: "13800138000"
});
三、核心数据结构解析
对于 Node.js 开发者,处理天远API 返回的数据时,最核心的工作是将 Array 转换为 Object (Map)。
1. 原始数据困境
API 返回的数据是为了传输效率优化的 2:
JavaScript
json
"riskInfo_report_v3.1": [
{ "riskCode": "41001", "riskCodeValue": "43" }, // 需要遍历才能找到
{ "riskCode": "40105", "riskCodeValue": "5" }
]
2. 清洗后的数据优势
通过 reduce 函数转换后,我们可以直接通过 Key 访问,这在编写风控规则引擎(Rule Engine)时至关重要:
JavaScript
kotlin
{
"41001": 43,
"40105": 5,
"41005": 34
}
// 规则书写变得极其简单:
if (data['41001'] > 80) return reject();
四、字段详解(Node.js 实战关注点)
以下字段是开发 BFF 层接口时,最常需要 透传给前端 或 用于 网关拦截 的关键指标。
1. 宏观评分(用于前端展示或分流)
| 字段 Code | 字段含义 | 说明 | Node.js 处理建议 |
|---|---|---|---|
| 41001 | 多头申请通用分 | 0-100分 3 | 可直接透传给信审员后台展示。 |
| 41002 | 短周期多头共债子分 | 0-100分,窗口期7天-3个月 4 | 用于判断是否"近期突发缺钱"。 |
| 41005 | 银行多头共债子分 | 0-100分 5 | 银行系数据的权重,通常代表资质上限。 |
2. 行为特征(用于自动拦截)
| 字段 Code | 字段含义 | 阈值参考 | 业务逻辑 |
|---|---|---|---|
| 40105 | 7天总申请夜晚次数 | > 0 即关注 | 夜间(0点-7点)申请是典型的高危欺诈特征 6。 |
| 40161 | 7天相对过去30天新增平台数 | > 3 即预警 | 突然新增大量平台(撸口子),大概率是将要"跑路"的前兆 7。 |
| 40004 | 7天内互金申请次数 | High | 频繁申请P2P/网贷,意味着银行渠道已拒绝或额度耗尽 8。 |
五、应用价值分析
在 Node.js 架构中集成天远API的行业风险版,主要解决以下痛点:
-
分流策略(Routing):
在网关层,根据 41005 (银行分) 和 41004 (非银分) 的比值,将流量分发给不同的资金方。
- 银行分高 -> 路由至低息、大额资金方接口。
- 非银分高 -> 路由至高息、小额助贷机构接口。
-
反欺诈中间件:
开发一个 Express/Koa 中间件,在请求进入核心业务逻辑前,先调用 API 校验 40105 (夜间申请次数)。如果发现该指标异常,直接在中间件层返回 "Risk Reject",无需消耗后端复杂的授信计算资源,保护核心系统。
-
用户画像补全:
利用 Node.js 的高并发特性,批量清洗存量用户的 40037 (360天总申请次数) 和 40038 (360天银行申请次数) 9,计算出用户的"银行偏好度",用于精准营销。
六、总结
天远API 的多头借贷行业风险版,通过分行业、分时段的维度,为风控提供了"显微镜"级别的观察能力。
对于 Node.js 开发者,虽然需要处理 AES 加密和 Buffer 拼接的底层细节,但通过简单的封装(如本文的 Service 类),即可轻松获得强大的数据清洗能力。建议开发者在 BFF 层重点关注 夜间申请 (40105) 和 新增平台数 (40161) 这两个"杀手级"指标,它们往往是识别欺诈用户最有效的手段。