From 3f67db1028e3cb1d1bbbcedc4799fadd024e6345 Mon Sep 17 00:00:00 2001 From: "Apple\\Apple" Date: Tue, 10 Jun 2025 02:32:50 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20feat:=20implement=20GET=20request?= =?UTF-8?q?=20deduplication=20in=20API=20layer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add request deduplication mechanism to prevent duplicate GET requests to the same endpoint within the same timeframe, significantly reducing unnecessary network overhead. **Changes:** - Add `patchAPIInstance()` function to intercept and deduplicate GET requests - Implement in-flight request tracking using Map with URL+params as unique keys - Apply deduplication patch to both initial API instance and `updateAPI()` recreated instances - Add `disableDuplicate: true` config option to bypass deduplication when needed **Benefits:** - Eliminates redundant API calls caused by component re-renders or rapid user interactions - Reduces server load and improves application performance - Provides automatic protection against accidental duplicate requests - Maintains backward compatibility with existing code **Technical Details:** - Uses Promise sharing for identical concurrent requests - Automatically cleans up completed requests from tracking map - Preserves original axios functionality with minimal overhead - Zero breaking changes to existing API usage Addresses the issue observed in EditChannel.js where multiple calls were made to the same endpoints during component lifecycle. --- web/src/helpers/api.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/web/src/helpers/api.js b/web/src/helpers/api.js index eb70cd27..aef01287 100644 --- a/web/src/helpers/api.js +++ b/web/src/helpers/api.js @@ -12,6 +12,36 @@ export let API = axios.create({ }, }); +function patchAPIInstance(instance) { + const originalGet = instance.get.bind(instance); + const inFlightGetRequests = new Map(); + + const genKey = (url, config = {}) => { + const params = config.params ? JSON.stringify(config.params) : '{}'; + return `${url}?${params}`; + }; + + instance.get = (url, config = {}) => { + if (config?.disableDuplicate) { + return originalGet(url, config); + } + + const key = genKey(url, config); + if (inFlightGetRequests.has(key)) { + return inFlightGetRequests.get(key); + } + + const reqPromise = originalGet(url, config).finally(() => { + inFlightGetRequests.delete(key); + }); + + inFlightGetRequests.set(key, reqPromise); + return reqPromise; + }; +} + +patchAPIInstance(API); + export function updateAPI() { API = axios.create({ baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL @@ -22,6 +52,8 @@ export function updateAPI() { 'Cache-Control': 'no-store', }, }); + + patchAPIInstance(API); } API.interceptors.response.use(