共计 2849 个字符,预计需要花费 8 分钟才能阅读完成。
在数字化转型的浪潮中,企业越来越倾向于将 AI 能力如 ChatGPT 集成到自己的业务系统中。本文将详细介绍如何通过银联订阅方式集成 ChatGPT 服务,解决支付回调与 AI 对话的时序冲突等问题,并分享一套完整的 Spring Boot 集成方案。

背景痛点
企业接入银联订阅 ChatGPT 服务时,常遇到以下几个痛点:
- 支付回调与 ChatGPT 异步对话的时序冲突 :银联支付成功回调与 ChatGPT 的响应可能存在时间差,导致用户支付成功但未及时获得服务。
- 交易幂等性要求 :支付回调可能因网络问题重复触发,需要确保同一笔交易不会被重复处理。
- 敏感信息加密传输需求 :支付信息和用户对话内容涉及敏感数据,需要安全传输和存储。
技术选型
在技术选型上,我们对比了直接调用 OpenAI API 与银联订阅服务的差异:
- 成本 :银联订阅服务通常有更优惠的费率,适合高频使用场景。
- 合规性 :银联订阅服务符合国内金融支付规范,避免了直接调用国外 API 的合规风险。
- QPS:银联订阅服务提供了更高的 QPS(每秒查询率),适合高并发场景。
核心实现
使用 Spring WebFlux 处理银联异步通知
Spring WebFlux 是一个响应式编程框架,适合处理高并发的异步通知。通过 WebFlux,我们可以高效处理银联的支付回调请求。
JWS(JSON Web Signature) 验证银联回调合法性
银联回调请求会附带 JWS 签名,我们需要验证签名的合法性以确保请求来源可信。以下是验签代码片段:
public boolean verifySignature(String callbackData, String signature) {
try {JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) getPublicKey());
JWSObject jwsObject = JWSObject.parse(callbackData);
return jwsObject.verify(verifier);
} catch (Exception e) {log.error("验签失败", e);
return false;
}
}
Redis 分布式锁防止重复消费
为了防止同一笔交易被重复处理,我们使用 Redis 分布式锁来确保幂等性:
public boolean acquireLock(String transactionId) {
String lockKey = "lock:" + transactionId;
return redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", Duration.ofMinutes(5));
}
代码示例
银联回调控制器
@RestController
@RequestMapping("/api/callback")
public class UnionPayCallbackController {@PostMapping("/unionpay")
public Mono<ResponseEntity<String>> handleCallback(@RequestBody String callbackData, @RequestHeader("Signature") String signature) {if (!verifySignature(callbackData, signature)) {return Mono.just(ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("验签失败"));
}
// 处理回调逻辑
return Mono.just(ResponseEntity.ok("处理成功"));
}
}
ChatGPT 会话上下文管理类
public class ChatSessionManager {
private final RedisTemplate<String, Object> redisTemplate;
public void saveSession(String sessionId, ChatSession session) {redisTemplate.opsForValue().set("session:" + sessionId, session, Duration.ofHours(1));
}
public ChatSession getSession(String sessionId) {return (ChatSession) redisTemplate.opsForValue().get("session:" + sessionId);
}
}
敏感数据 AES-GCM 加密工具类
public class AesGcmEncryptor {public static String encrypt(String plaintext, String key) throws Exception {SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV();
byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
return Base64.getEncoder().encodeToString(iv) + ":" + Base64.getEncoder().encodeToString(ciphertext);
}
}
生产建议
银联商户私钥的 KMS 存储方案
建议使用 KMS(密钥管理服务)来存储银联商户私钥,避免硬编码在代码中。KMS 提供了密钥的安全存储和访问控制。
ChatGPT 流式响应时的背压控制
在处理 ChatGPT 的流式响应时,需要注意背压控制,防止服务端过载。可以通过 Reactive Streams 的背压机制来实现。
对话日志脱敏存储策略
对话日志中可能包含敏感信息,建议在存储前进行脱敏处理,例如替换或加密敏感字段。
延伸思考
如何扩展此架构以支持多 AI 供应商动态切换?
可以通过策略模式来实现多 AI 供应商的动态切换。定义一个统一的 AI 服务接口,不同的 AI 供应商实现该接口。在运行时根据配置或条件选择具体的实现。
sequenceDiagram
participant 银联
participant 企业服务
participant ChatGPT
银联 ->> 企业服务: 支付回调
企业服务 ->> 企业服务: 验签
企业服务 ->> 企业服务: 幂等性检查
企业服务 ->>ChatGPT: 调用 AI 服务
ChatGPT-->> 企业服务: 返回响应
企业服务 -->> 银联: 回调确认
通过以上步骤,我们实现了一个高效、安全的企业级 ChatGPT 集成方案。希望这篇指南能帮助你在实际项目中顺利接入银联订阅 ChatGPT 服务。
