摘要:跨境电商独立站需要支持多语言、多币种。本文介绍如何设计汇率微服务,对接外部API(如阿里云外汇汇率API),使用Redis缓存降低调用成本,并保证高并发下的实时换算性能。Taoify跨境电商的汇率系统每天处理百万次换算请求。
一、系统架构
汇率服务分为三层:采集层——定时拉取实时汇率并存入数据库/Redis;缓存层——Redis存储最新汇率,TTL为2小时;计算层——提供REST接口,接收金额、源货币、目标货币,返回换算结果。
二、汇率采集
java
@Componentpublic class ExchangeRateCollector { @Autowired private RedisTemplate redisTemplate; // 每2小时执行一次 @Scheduled(cron = "0 0 /2 * ?") public void collect() { // 调用阿里云外汇汇率API String url = "https://market.aliyun.com/apimarket/detail?productId=xxx"; RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "APPCODE " + APP_CODE); HttpEntity entity = new HttpEntity<>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, RateResponse.class); Map rates = response.getBody().getRates(); // 存储到Redis,Hash结构 redisTemplate.opsForHash().putAll("exchange_rates", rates); // 同时存储一份到数据库,用于历史追溯 saveToDatabase(rates); }}
三、汇率换算接口
java
@RestControllerpublic class ExchangeController { @Autowired private RedisTemplate redisTemplate; @GetMapping("/exchange") public ExchangeResult convert(@RequestParam BigDecimal amount, @RequestParam String from, @RequestParam String to) { // 基准货币为CNY,先转为CNY,再转为目标货币 BigDecimal cnyAmount; if (!"CNY".equals(from)) { BigDecimal fromRate = getRate(from); cnyAmount = amount.divide(fromRate, 2, RoundingMode.HALF_UP); } else { cnyAmount = amount; } if ("CNY".equals(to)) { return new ExchangeResult(cnyAmount); } BigDecimal toRate = getRate(to); BigDecimal result = cnyAmount.multiply(toRate); return new ExchangeResult(result.setScale(2, RoundingMode.HALF_UP)); } private BigDecimal getRate(String currency) { String rateStr = (String) redisTemplate.opsForHash().get("exchange_rates", currency); if (rateStr == null) { throw new BusinessException("不支持的货币类型"); } return new BigDecimal(rateStr); }}
四、前端多货币展示优化
Taoify跨境电商的前端商品价格不再每次实时换算,而是利用CDN缓存静态价格。当用户切换货币时,前端调用汇率接口批量刷新页面价格,减少接口调用。
javascript
// 前端批量换算async function convertPrices(targetCurrency) { const amounts = collectAllPrices(); const response = await fetch('/exchange/batch', { method: 'POST', body: JSON.stringify({ amounts, targetCurrency }) }); const converted = await response.json(); updatePrices(converted);}
后端批量接口使用CompletableFuture并发调用缓存,将RT从串行的500ms降低到50ms。