【架构实战】移动端网络优化:弱网加速方案

一、移动端网络特点

移动网络面临诸多挑战:

网络特点:

  • 高延迟(2G: 400ms, 3G: 100ms, 4G: 20ms)
  • 不稳定(频繁切换、信号强弱变化)
  • 带宽有限
  • 流量成本高

二、弱网检测

1. 网络状态监听

javascript 复制代码
// React Native网络检测
import NetInfo from "@react-native-community/netinfo";

useEffect(() => {
  const unsubscribe = NetInfo.addEventListener(state => {
    console.log("Connection type:", state.type);
    console.log("Is connected?:", state.isConnected);
    
    // 检测网络类型
    if (state.type === 'cellular') {
      console.log("当前使用移动网络");
      if (state.details.isConnectionExpensive) {
        console.log("节省流量模式");
      }
    }
  });
  
  return () => unsubscribe();
}, []);

// 获取当前网络信息
const checkNetwork = async () => {
  const state = await NetInfo.fetch();
  return state;
};

2. 智能重试机制

java 复制代码
// Android OkHttp拦截器
public class RetryInterceptor implements Interceptor {
    
    private static final int MAX_RETRIES = 3;
    private static final long RETRY_DELAY_MS = 1000;
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        IOException lastException = null;
        
        for (int attempt = 0; attempt < MAX_RETRIES; attempt++) {
            try {
                response = chain.proceed(request);
                
                if (response.isSuccessful()) {
                    return response;
                }
                
                // 如果是可重试的错误码
                if (isRetryable(response.code())) {
                    response.close();
                    continue;
                }
                
                return response;
                
            } catch (IOException e) {
                lastException = e;
                
                // 检测网络是否可用
                if (!isNetworkAvailable()) {
                    throw new NoNetworkException("网络不可用");
                }
                
                // 指数退避
                if (attempt < MAX_RETRIES - 1) {
                    try {
                        Thread.sleep(RETRY_DELAY_MS * (attempt + 1));
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
        
        throw lastException;
    }
    
    private boolean isRetryable(int code) {
        return code >= 500 || code == 408 || code == 429;
    }
}

三、请求优化

1. 请求合并

typescript 复制代码
// Flutter请求合并
class RequestBatcher {
  private pendingRequests = new Map<string, Promise<any>>();
  private batchTimer: NodeJS.Timeout | null = null;
  private readonly BATCH_DELAY = 50; // 50ms内合并请求
  
  async batchRequest<T>(key: string, request: () => Promise<T>): Promise<T> {
    // 如果已有相同请求在处理中,返回同一个Promise
    if (this.pendingRequests.has(key)) {
      return this.pendingRequests.get(key) as Promise<T>;
    }
    
    const promise = request();
    this.pendingRequests.set(key, promise);
    
    // 延迟清理
    setTimeout(() => {
      this.pendingRequests.delete(key);
    }, this.BATCH_DELAY);
    
    return promise;
  }
}

2. 请求优先级

typescript 复制代码
// 请求优先级队列
enum RequestPriority {
  HIGH = 0,   // 用户操作相关,如点击、滑动
  NORMAL = 1, // 普通数据请求
  LOW = 2     // 预加载、统计等
}

class PriorityRequestQueue {
  private queues: Map<RequestPriority, Queue[]> = new Map([
    [RequestPriority.HIGH, []],
    [RequestPriority.NORMAL, []],
    [RequestPriority.LOW, []]
  ]);
  
  addRequest(request: () => Promise<any>, priority: RequestPriority) {
    const queue = this.queues.get(priority)!;
    return new Promise((resolve, reject) => {
      queue.push({ request, resolve, reject });
      this.processQueue();
    });
  }
  
  private async processQueue() {
    for (const [priority, queue] of this.queues) {
      while (queue.length > 0) {
        const { request, resolve, reject } = queue.shift()!;
        try {
          const result = await request();
          resolve(result);
        } catch (e) {
          reject(e);
        }
        
        // 高优先级请求可以中断低优先级
        if (priority === RequestPriority.HIGH) {
          break;
        }
      }
    }
  }
}

四、数据压缩

1. 请求体压缩

typescript 复制代码
// Flutter请求压缩
import { gzip } from 'pako';

class CompressedHttpClient {
  
  async postCompressed<T>(url: string, data: any): Promise<T> {
    const jsonString = JSON.stringify(data);
    const compressed = gzip(jsonString);
    
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Encoding': 'gzip',
        'Content-Type': 'application/json'
      },
      body: compressed
    });
    
    return response.json();
  }
}

2. 响应压缩处理

typescript 复制代码
// 处理压缩响应
async function fetchDecompressed(url: string): Promise<any> {
  const response = await fetch(url);
  
  const contentEncoding = response.headers.get('Content-Encoding');
  let data;
  
  if (contentEncoding === 'gzip') {
    const buffer = await response.arrayBuffer();
    const decompressed = ungzip(buffer);
    const text = new TextDecoder().decode(decompressed);
    data = JSON.parse(text);
  } else if (contentEncoding === 'br') {
    const buffer = await response.arrayBuffer();
    const decompressed = brotliDecompress(buffer);
    const text = new TextDecoder().decode(decompressed);
    data = JSON.parse(text);
  } else {
    data = await response.json();
  }
  
  return data;
}

五、本地缓存

1. SQLite缓存

java 复制代码
// Android Room缓存
@Entity(tableName = "api_cache")
public class ApiCache {
    @PrimaryKey
    public String key;
    public String response;
    public long timestamp;
    public long expireTime;
}

@Dao
public interface ApiCacheDao {
    
    @Query("SELECT * FROM api_cache WHERE key = :key AND timestamp + expireTime > :currentTime")
    ApiCache getValidCache(String key, long currentTime);
    
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(ApiCache cache);
    
    @Query("DELETE FROM api_cache WHERE timestamp + expireTime < :currentTime")
    void deleteExpired(long currentTime);
}

public class CacheRepository {
    
    public <T> T getOrFetch(String key, long expireMs, Supplier<T> fetcher) {
        // 查缓存
        long currentTime = System.currentTimeMillis();
        ApiCache cache = cacheDao.getValidCache(key, currentTime);
        
        if (cache != null) {
            return parseJson(cache.response);
        }
        
        // 缓存未命中,请求网络
        T result = fetcher.get();
        
        // 存入缓存
        ApiCache newCache = new ApiCache();
        newCache.key = key;
        newCache.response = toJson(result);
        newCache.timestamp = currentTime;
        newCache.expireTime = expireMs;
        cacheDao.insert(newCache);
        
        return result;
    }
}

2. MMKV高速缓存

typescript 复制代码
// React Native MMKV
import { MMKV } from 'react-native-mmkv';

const storage = new MMKV({
  id: 'api-cache'
});

class MMKVCache {
  
  set<T>(key: string, value: T, expireMs?: number): void {
    const data = {
      value,
      expireTime: expireMs ? Date.now() + expireMs : null
    };
    storage.set(key, JSON.stringify(data));
  }
  
  get<T>(key: string): T | null {
    const json = storage.getString(key);
    if (!json) return null;
    
    const data = JSON.parse(json);
    
    if (data.expireTime && Date.now() > data.expireTime) {
      storage.delete(key);
      return null;
    }
    
    return data.value;
  }
}

六、离线优先

1. Service Worker缓存策略

javascript 复制代码
// Flutter Service Worker
const CACHE_NAME = 'app-cache-v1';
const OFFLINE_URL = '/offline.html';

// 缓存策略:Cache First
self.addEventListener('fetch', event => {
  if (event.request.mode === 'navigate') {
    event.respondWith(
      fetch(event.request).catch(() => {
        return caches.match(OFFLINE_URL);
      })
    );
    return;
  }
  
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request).then(fetchResponse => {
        return caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, fetchResponse.clone());
          return fetchResponse;
        });
      });
    })
  );
});

2. 离线数据同步

typescript 复制代码
// 离线数据队列
class OfflineQueue {
  private queue: OfflineRequest[] = [];
  
  // 网络离线时,存入队列
  async enqueue(request: OfflineRequest) {
    this.queue.push(request);
    await this.persist();
  }
  
  // 网络恢复后,同步队列
  async sync() {
    const pending = [...this.queue];
    
    for (const request of pending) {
      try {
        await this.execute(request);
        // 成功后移除
        this.queue = this.queue.filter(r => r.id !== request.id);
      } catch (e) {
        // 失败后重试
        request.retryCount++;
        if (request.retryCount >= 3) {
          // 重试超过3次,标记失败
          await this.markFailed(request);
          this.queue = this.queue.filter(r => r.id !== request.id);
        }
      }
    }
    
    await this.persist();
  }
}

七、弱网体验优化

1.骨架屏

tsx 复制代码
// React骨架屏
const ProductCardSkeleton = () => (
  <View style={styles.card}>
    <View style={styles.imageSkeleton} />
    <View style={styles.titleSkeleton} />
    <View style={styles.priceSkeleton} />
  </View>
);

const ProductCard = ({ product, isLoading }) => {
  if (isLoading) {
    return <ProductCardSkeleton />;
  }
  
  return (
    <View style={styles.card}>
      <Image source={{ uri: product.image }} />
      <Text>{product.title}</Text>
      <Text>¥{product.price}</Text>
    </View>
  );
};

2. 渐进式加载

tsx 复制代码
// 图片渐进式加载
const ProgressiveImage = ({ uri, style }) => {
  const [loaded, setLoaded] = useState(false);
  const [error, setError] = useState(false);
  
  return (
    <View style={style}>
      {/* 先显示缩略图 */}
      <Image 
        source={{ uri: uri + '?w=50&h=50&fit=cover' }}
        style={[style, { opacity: loaded ? 1 : 0 }]}
        onLoad={() => setLoaded(true)}
      />
      {/* 占位图 */}
      {!loaded && !error && (
        <View style={[styles.placeholder, style]} />
      )}
    </View>
  );
};

八、总结

移动端网络优化提升用户体验:

  • 网络检测:实时感知网络状态
  • 智能重试:指数退避提高成功率
  • 数据压缩:减少流量消耗
  • 本地缓存:减少网络请求
  • 离线优先:弱网也能使用

最佳实践:

  1. 做好网络状态检测
  2. 实现智能重试机制
  3. 使用本地缓存减少请求
  4. 优化弱网下的用户体验

个人观点,仅供参考

相关推荐
数字孪生进化论2 小时前
数字孪生渲染架构深度对比:端渲染 vs 流渲染 vs 双模融合
架构
万岳科技系统开发2 小时前
商城系统搭建自建平台与入驻第三方平台对比分析
数据库·小程序·架构
2501_933329553 小时前
技术深度拆解:Infoseek舆情处置系统的全链路架构与核心实现
开发语言·人工智能·自然语言处理·架构
2601_949925183 小时前
基于 OpenClaw 打造货代行业 AI 智能体架构实战
大数据·人工智能·架构·ai智能体
无心水4 小时前
OpenClaw技术文档/代码评审/测试用例生成深度实战
网络·后端·架构·测试用例·openclaw·养龙虾
数智顾问4 小时前
(107页PPT)数字化转型企业架构设计业务架构应用架构数据架构技术架构(附下载方式)
架构
Ai173163915794 小时前
GB200 NVL72超节点深度解析:架构、生态与产业格局
大数据·服务器·人工智能·神经网络·机器学习·计算机视觉·架构
一个有温度的技术博主5 小时前
微服务4:Spring Cloud 微服务实战:如何实现跨服务数据组装?
spring cloud·微服务·架构
好家伙VCC6 小时前
**基于RISC-V架构的嵌入式系统开发:从零开始构建高效低功耗应用**在当前物联网(IoT)和边缘计
java·python·物联网·架构·risc-v