Node.js 全栈进阶:基于天远 API 实现动态化的用户消费分级策略

22 阅读5分钟

从“千人一面”到“千人千面”:实时风控的最后一公里

在现代 Web 应用开发中,用户体验的竞争已经从“界面美观”卷到了“服务精准”。当一个用户点击“申请额度”或“查看权益”时,前端需要的不仅仅是一个 Loading 动画,而是后端能毫秒级地根据用户的真实购买力,返回定制化的结果。

天远个人消费能力等级 API 为 Node.js 开发者提供了一个强大的工具。通过简单的 HTTP 调用,即可获取用户量化后的收入指数(100-1000分)。这意味着我们可以在 BFF (Backend for Frontend) 层直接根据分数决定前端渲染逻辑:是给用户展示“黑金卡入口”,还是引导去“新手专区”。

Node.js (TypeScript) 集成:异步流与加密实战

Node.js 的非阻塞 I/O 特性使其非常适合处理此类高并发的 API 请求。但在对接过程中,最大的“坑”往往在于加密算法的实现。API 要求使用 AES-128-CBC 模式,并进行 PKCS7 填充。

以下是基于 TypeScript 的生产级代码示例,使用了 Node.js 原生 crypto 模块,无需引入庞大的第三方加密库。

1. 环境准备与类型定义

首先,我们需要定义清晰的接口类型,以利用 TypeScript 的静态检查优势。

TypeScript

// types.ts
export interface UserCapacityRequest {
  mobile_no: string;
  id_card: string;
  name: string;
}

export interface ApiRawResponse {
  code: number; // 0 表示成功
  message: string;
  transaction_id: string;
  data: string; // 加密后的响应数据
  personincome_index_2_0?: string; // 解密后映射的字段
}

// 业务配置
const CONFIG = {
  API_URL: "<https://api.tianyuanapi.com/api/v1/JRZQ8B3C>",
  ACCESS_ID: process.env.TIANYUAN_ACCESS_ID || "",
  ACCESS_KEY: process.env.TIANYUAN_ACCESS_KEY || "", // 16位密钥
};

2. 核心加密服务 (CryptoService)

Node.js 的 crypto 模块默认处理填充的方式与 Java/Python 略有不同,这里我们需要显式处理 IV 的拼接和 Base64 编码。

TypeScript

import * as crypto from 'crypto';

class CryptoService {
  private algorithm = 'aes-128-cbc';
  private key: Buffer;

  constructor(secretKey: string) {
    // 确保密钥长度为16字节,根据实际Key格式可能需要 Buffer.from(key, 'hex')
    this.key = Buffer.from(secretKey, 'utf8'); 
  }

  /**
   * 加密逻辑:IV (16bytes) + AES加密内容 -> Base64
   */
  public encrypt(data: object): string {
    const iv = crypto.randomBytes(16); // 生成随机IV 
    const jsonStr = JSON.stringify(data);

    const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
    let encrypted = cipher.update(jsonStr, 'utf8', 'base64');
    encrypted += cipher.final('base64');

    // 注意:Node.js加密后的输出如果是base64,拼接时需小心。
    // 更稳妥的方式是操作Buffer:
    const cipherBuffer = crypto.createCipheriv(this.algorithm, this.key, iv);
    const encryptedBuffer = Buffer.concat([
      cipherBuffer.update(jsonStr, 'utf8'),
      cipherBuffer.final()
    ]);

    // 拼接 IV + 密文 -> Base64 
    const resultBuffer = Buffer.concat([iv, encryptedBuffer]);
    return resultBuffer.toString('base64');
  }
}

3. API 调用与业务封装

使用 axios 处理网络请求,利用 async/await 保持代码的整洁。

TypeScript

import axios from 'axios';

async function checkUserCapacity(userInfo: UserCapacityRequest) {
  const cryptoService = new CryptoService(CONFIG.ACCESS_KEY);

  try {
    // 1. 加密请求体
    const encryptedData = cryptoService.encrypt(userInfo);

    // 2. 发起请求
    // URL中需携带时间戳 t 
    const url = `${CONFIG.API_URL}?t=${Date.now()}`;
    
    const response = await axios.post<ApiRawResponse>(
      url,
      { data: encryptedData },
      {
        headers: {
          'Access-Id': CONFIG.ACCESS_ID,
          'Content-Type': 'application/json' // axios默认json,也可手动指定
        },
        timeout: 5000 // 建议设置超时
      }
    );

    const result = response.data;

    // 3. 处理响应
    if (result.code === 0) {
        // TODO: 此处需实现解密逻辑 (逻辑与加密相反:Base64 decode -> 提取前16位IV -> 解密)
        // 假设解密并解析JSON后得到了 decryptedObj
        // return decryptedObj.personincome_index_2_0; 
        console.log(`查询成功,流水号: ${result.transaction_id}`);
        return result; 
    } else {
        console.warn(`业务异常: ${result.message} (Code: ${result.code})`);
        return null;
    }

  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('网络请求失败:', error.message);
    } else {
      console.error('未知错误:', error);
    }
    throw error;
  }
}

数据解析:JSON 里的玄机

在全栈开发中,处理 API 返回的 JSON 数据是家常便饭,但对于天远 API 的返回值,有几个细节需要特别留意,以免在前端展示时出现 NaNundefined 错误。

字段名类型示例前端展示建议
personincome_index_2.0String"650"必须转为 Number。不要直接用于数学比较。
codeNumber1000Code 1000 = 查询为空。前端应展示“暂无数据”或引导用户补充资料,而不是报错。
-1 (特殊值)String"-1"表示未命中。建议 UI 降级处理,不展示评分卡片。

评分与用户分层的映射逻辑

根据文档,评分与收入区间的关系如下。建议在 BFF 层将其转化为具体的 UserTier 枚举,供前端直接使用:

  • Tier 1 (基础): 100-300分 (月入 < 6k) -> 对应策略:基础版界面,锁定高阶功能。
  • Tier 2 (中产): 400-600分 (月入 6k-12k) -> 对应策略:标准版界面,推送分期服务。
  • Tier 3 (高端): 700-1000分 (月入 12k+) -> 对应策略:尊享版界面,专属客服入口。

场景延伸:Node.js 驱动的实时业务流

利用 Node.js 的事件驱动特性,我们可以将该 API 的价值最大化:

  1. 电商大促的“流量漏斗” (Traffic Filtering)

    在双11等大促场景下,为了防止羊毛党通过脚本抢占高价值优惠券,可以在领券接口的中间件(Middleware)中接入此 API。对于 personincome_index_2.0 低于 200 分且行为异常的用户,直接在后端拦截或弹出图形验证码,保留服务器资源给真实的高潜用户。

  2. BNPL (先买后付) 实时准入

    在支付收银台,当用户选择“分期付款”时,Node.js 服务端实时调用接口。

    • < 400分:前端置灰“分期支付”按钮,仅允许全额支付。
    • > 600分:默认勾选“3期免息”,利用“损失厌恶”心理提高客单价。
  3. 冷启动用户的个性化推荐

    对于刚注册的新用户,推荐系统往往因为缺乏行为数据而失效(冷启动问题)。接入此 API 后,虽然没有浏览记录,但我们知道他的消费能力等级。如果是 900 分的用户,推荐流可以直接从“9.9包邮”切换为“今日大牌”,大幅提升首单转化率。

结语

在“体验为王”的 Web 开发时代,数据的价值在于实时性。通过 Node.js 高效集成天远个人消费能力等级 API,我们不再是被动地接收用户请求,而是能在用户交互的毫秒间,主动识别用户价值,提供差异化的服务。这不仅是代码层面的优化,更是业务逻辑的升维。