You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native+Go架构下API重复调用问题:寻求即时处理替代方案

解决方案:实现API2的即时/低延迟精准调用(避免重复执行)

针对你遇到的「Google定位重复触发API1调用,导致API2重复执行」问题,以下几个方案可以在保证去重的同时,实现API2的即时或低延迟执行:

一、移动端侧提前过滤重复触发

从源头减少重复请求是最有效的方式:

  • 防抖+区域确认:使用防抖函数(比如lodash.debounce)包裹定位回调,当用户离开目标区域后,延迟1-2秒再确认位置状态,如果用户确实持续在区域外,再调用API1。同时在本地记录「已触发离开事件」的状态,短时间内(比如5分钟)不再重复发起请求。
    示例(React Native):
    import { debounce } from 'lodash';
    let hasTriggeredLeave = false;
    
    const handleLocationChange = debounce(async (location) => {
      if (isOutsideTargetArea(location) && !hasTriggeredLeave) {
        hasTriggeredLeave = true;
        await fetch('/api1', { method: 'POST', body: JSON.stringify({ location }) });
        // 5分钟后重置状态,允许再次触发
        setTimeout(() => hasTriggeredLeave = false, 5 * 60 * 1000);
      }
    }, 2000); // 2秒防抖延迟
    

二、API1侧实现请求幂等性

在后端层面拦截重复请求,确保同一个事件只处理一次:

  • 基于唯一请求ID的幂等校验:要求移动端在调用API1时,携带一个客户端生成的唯一标识(比如UUID或设备ID+时间戳的哈希值),放在请求头(如X-Request-ID)或请求体中。API1接收到请求后,先检查这个ID是否已经被处理过(用Redis或内存缓存存储已处理的ID,设置过期时间覆盖重复触发窗口),如果已处理直接返回成功,否则执行后续逻辑并标记该ID为已处理。
    示例(Go):
    import "github.com/go-redis/redis/v8"
    import "time"
    
    func API1Handler(w http.ResponseWriter, r *http.Request) {
      ctx := r.Context()
      reqID := r.Header.Get("X-Request-ID")
      if reqID == "" {
        http.Error(w, "missing X-Request-ID", http.StatusBadRequest)
        return
      }
    
      // 检查请求是否已处理
      processed, err := redisClient.Get(ctx, "processed:"+reqID).Result()
      if err == nil && processed == "true" {
        w.WriteHeader(http.StatusOK)
        return
      }
    
      // 调用API2
      callAPI2()
    
      // 标记请求已处理,设置10分钟过期
      redisClient.SetEx(ctx, "processed:"+reqID, "true", 10*time.Minute)
      w.WriteHeader(http.StatusOK)
    }
    

三、用消息队列替代定时轮询,实现异步即时处理

将「缓存到数据库+定时轮询」的模式替换为「消息队列+即时消费」,既保留异步解耦,又能低延迟处理:

  • API1接收到请求后,先做幂等校验(同方案二),然后将任务发送到消息队列(如Redis List、RabbitMQ、NATS)。
  • 单独启动一个Go消费进程,持续监听队列,一旦有新任务就取出,再次校验幂等(避免队列重复投递),然后调用API2。
  • 这种方式可以做到秒级甚至毫秒级的延迟,同时消息队列的ACK机制可以保证任务不丢失。

四、分布式锁控制并发执行

如果同一设备的多个API1请求可能同时到达,用分布式锁确保同一时间只有一个请求调用API2:

  • API1接收到请求后,以设备ID为锁的key,尝试获取分布式锁(比如基于Redis的Redlock),锁的有效期设置为API2执行所需的最长时间(比如30秒)。
  • 如果获取到锁,就调用API2;如果获取失败,说明已有请求在处理,直接返回成功即可。
    示例(Go,使用redsync):
    import "github.com/go-redsync/redsync/v4"
    import "time"
    
    func API1Handler(w http.ResponseWriter, r *http.Request) {
      deviceID := r.FormValue("device_id")
      if deviceID == "" {
        http.Error(w, "missing device_id", http.StatusBadRequest)
        return
      }
    
      // 创建分布式锁
      mutex := rsync.NewMutex("lock:"+deviceID, redsync.New(redsync.WithPool(redisClient)))
      // 尝试获取锁,最多等待1秒,锁有效期30秒
      if err := mutex.LockContext(r.Context(), 1*time.Second, 30*time.Second); err != nil {
        w.WriteHeader(http.StatusOK)
        return
      }
      defer mutex.Unlock()
    
      // 调用API2
      callAPI2()
      w.WriteHeader(http.StatusOK)
    }
    

方案选型建议

  • 如果移动端的重复触发是主要原因,优先选方案一+方案二,从源头和后端双重拦截。
  • 如果需要异步解耦且低延迟,选方案二+方案三,兼顾去重和即时处理。
  • 如果存在并发请求导致的重复执行,选方案四配合幂等校验。

内容的提问来源于stack exchange,提问作者Amandeep kaur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:05:01