021、深入解析前端请求拦截器

news2024/12/24 19:25:03

目录

深入解析前端请求拦截器:

1. 引言

2. 核心实现与基础概念

2.1 基础拦截器实现

2.2 响应拦截器配置

3. 实际应用场景

3.1 完整的用户认证系统

3.2 文件上传系统

3.3 API请求缓存系统

3.4 请求重试机制

3.5 国际化处理

4. 性能优化实践

4.1 请求合并(Request Batching)

4.2 预请求与预加载

5. 安全性实践

5.1 XSS防护

5.2 CSRF防护

6. 监控与日志

6.1 请求监控系统

6.2 性能追踪系统

7. 高级应用场景

7.1 GraphQL请求处理

7.2 WebSocket 集成

7.3 离线请求队列

8. 微服务架构支持

9. 参考文献

10. 总结


深入解析前端请求拦截器:

1. 引言

在现代Web应用开发中,请求拦截器已成为处理HTTP请求的核心组件。根据Stack Overflow 2023年开发者调查报告,超过70%的企业级应用采用了请求拦截器进行统一的请求处理。本文将从多个维度深入分析请求拦截器的实现原理和最佳实践。

2. 核心实现与基础概念

2.1 基础拦截器实现
request.interceptors.request.use(config => {
 ? ?config.headers['Content-Type'] = 'application/json;charset=utf-8';
 ? ?let user = JSON.parse(localStorage.getItem("xm-user") || '{}')
 ? ?config.headers['token'] = user.token || ''
 ? ?return config
}, error => {
 ? ?return Promise.reject(error)
});
2.2 响应拦截器配置
request.interceptors.response.use(
 ? ?response => {
 ? ? ? ?// 统一处理响应
 ? ? ? ?const { code, data, message } = response.data;
 ? ? ? ?if (code === 200) {
 ? ? ? ? ? ?return data;
 ? ? ?  } else if (code === 401) {
 ? ? ? ? ? ?// 处理认证失败
 ? ? ? ? ? ?router.push('/login');
 ? ? ? ? ? ?return Promise.reject(new Error('认证失败'));
 ? ? ?  } else {
 ? ? ? ? ? ?Message.error(message);
 ? ? ? ? ? ?return Promise.reject(new Error(message));
 ? ? ?  }
 ?  },
 ? ?error => {
 ? ? ? ?// 处理网络错误
 ? ? ? ?if (error.response) {
 ? ? ? ? ? ?switch (error.response.status) {
 ? ? ? ? ? ? ? ?case 404:
 ? ? ? ? ? ? ? ? ? ?Message.error('请求的资源不存在');
 ? ? ? ? ? ? ? ? ? ?break;
 ? ? ? ? ? ? ? ?case 500:
 ? ? ? ? ? ? ? ? ? ?Message.error('服务器内部错误');
 ? ? ? ? ? ? ? ? ? ?break;
 ? ? ? ? ? ? ? ?default:
 ? ? ? ? ? ? ? ? ? ?Message.error('网络错误');
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?return Promise.reject(error);
 ?  }
);

3. 实际应用场景

3.1 完整的用户认证系统
// 认证服务
const authService = {
 ? ?async login(credentials) {
 ? ? ? ?try {
 ? ? ? ? ? ?const response = await request.post('/auth/login', credentials);
 ? ? ? ? ? ?this.storeUserData(response.data);
 ? ? ? ? ? ?return response;
 ? ? ?  } catch (error) {
 ? ? ? ? ? ?this.handleAuthError(error);
 ? ? ?  }
 ?  },
?
 ? ?storeUserData(data) {
 ? ? ? ?const encryptedToken = this.encryptSensitiveData(data.token);
 ? ? ? ?localStorage.setItem('xm-user', JSON.stringify({
 ? ? ? ? ? ?token: encryptedToken,
 ? ? ? ? ? ?expires: new Date().getTime() + 3600000,
 ? ? ? ? ? ?refreshToken: data.refreshToken
 ? ? ?  }));
 ?  },
?
 ? ?encryptSensitiveData(data) {
 ? ? ? ?// 使用AES加密敏感数据
 ? ? ? ?return CryptoJS.AES.encrypt(data, SECRET_KEY).toString();
 ?  },
?
 ? ?async refreshToken() {
 ? ? ? ?const userData = JSON.parse(localStorage.getItem('xm-user') || '{}');
 ? ? ? ?if (this.isTokenExpiring(userData)) {
 ? ? ? ? ? ?const response = await request.post('/auth/refresh-token', {
 ? ? ? ? ? ? ? ?refreshToken: userData.refreshToken
 ? ? ? ? ?  });
 ? ? ? ? ? ?this.storeUserData(response.data);
 ? ? ?  }
 ?  },
?
 ? ?isTokenExpiring(userData) {
 ? ? ? ?const bufferTime = 5 * 60 * 1000; // 5分钟缓冲时间
 ? ? ? ?return userData.expires - new Date().getTime() < bufferTime;
 ?  }
};
3.2 文件上传系统
// 文件上传服务
const uploadService = {
 ? ?// 文件上传拦截器配置
 ? ?setupInterceptor() {
 ? ? ? ?request.interceptors.request.use(config => {
 ? ? ? ? ? ?if (config.url.includes('/upload')) {
 ? ? ? ? ? ? ? ?config.headers['Content-Type'] = 'multipart/form-data';
 ? ? ? ? ? ? ? ?config.timeout = 30000;
 ? ? ? ? ? ? ? ?config.onUploadProgress = this.handleProgress;
 ? ? ? ? ?  }
 ? ? ? ? ? ?return config;
 ? ? ?  });
 ?  },
?
 ? ?handleProgress(progressEvent) {
 ? ? ? ?const percentCompleted = Math.round(
 ? ? ? ? ?  (progressEvent.loaded * 100) / progressEvent.total
 ? ? ?  );
 ? ? ? ?// 更新上传进度UI
 ? ? ? ?this.updateProgressBar(percentCompleted);
 ?  },
?
 ? ?async uploadFile(file, options = {}) {
 ? ? ? ?const formData = new FormData();
 ? ? ? ?formData.append('file', file);
 ? ? ? ?
 ? ? ? ?// 添加额外的元数据
 ? ? ? ?if (options.metadata) {
 ? ? ? ? ? ?formData.append('metadata', JSON.stringify(options.metadata));
 ? ? ?  }
?
 ? ? ? ?try {
 ? ? ? ? ? ?const response = await request.post('/api/upload', formData, {
 ? ? ? ? ? ? ? ?headers: {
 ? ? ? ? ? ? ? ? ? ?'X-File-Name': file.name,
 ? ? ? ? ? ? ? ? ? ?'X-File-Size': file.size
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  });
 ? ? ? ? ? ?return response.data;
 ? ? ?  } catch (error) {
 ? ? ? ? ? ?this.handleUploadError(error);
 ? ? ?  }
 ?  },
?
 ? ?async uploadChunked(file) {
 ? ? ? ?const chunkSize = 1024 * 1024; // 1MB chunks
 ? ? ? ?const chunks = Math.ceil(file.size / chunkSize);
 ? ? ? ?
 ? ? ? ?for (let i = 0; i < chunks; i++) {
 ? ? ? ? ? ?const chunk = file.slice(
 ? ? ? ? ? ? ? ?i * chunkSize,
 ? ? ? ? ? ? ? ?Math.min((i + 1) * chunkSize, file.size)
 ? ? ? ? ?  );
 ? ? ? ? ? ?await this.uploadChunk(chunk, i, chunks);
 ? ? ?  }
 ?  }
};
3.3 API请求缓存系统
// 高级缓存管理
class CacheManager {
 ? ?constructor() {
 ? ? ? ?this.cache = new Map();
 ? ? ? ?this.setupInterceptor();
 ?  }
?
 ? ?setupInterceptor() {
 ? ? ? ?request.interceptors.request.use(async config => {
 ? ? ? ? ? ?if (config.method === 'get' && config.cache !== false) {
 ? ? ? ? ? ? ? ?const cacheKey = this.generateCacheKey(config);
 ? ? ? ? ? ? ? ?const cachedResponse = this.getCache(cacheKey);
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?if (cachedResponse) {
 ? ? ? ? ? ? ? ? ? ?return Promise.resolve(cachedResponse);
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ? ? ? ?return config;
 ? ? ?  });
?
 ? ? ? ?request.interceptors.response.use(response => {
 ? ? ? ? ? ?if (response.config.method === 'get' && response.config.cache !== false) {
 ? ? ? ? ? ? ? ?const cacheKey = this.generateCacheKey(response.config);
 ? ? ? ? ? ? ? ?this.setCache(cacheKey, response);
 ? ? ? ? ?  }
 ? ? ? ? ? ?return response;
 ? ? ?  });
 ?  }
?
 ? ?generateCacheKey(config) {
 ? ? ? ?return `${config.url}-${JSON.stringify(config.params || {})}-${JSON.stringify(config.data || {})}`;
 ?  }
?
 ? ?getCache(key) {
 ? ? ? ?const cached = this.cache.get(key);
 ? ? ? ?if (!cached) return null;
?
 ? ? ? ?const { data, timestamp, maxAge } = cached;
 ? ? ? ?if (new Date().getTime() - timestamp > maxAge) {
 ? ? ? ? ? ?this.cache.delete(key);
 ? ? ? ? ? ?return null;
 ? ? ?  }
 ? ? ? ?return data;
 ?  }
?
 ? ?setCache(key, data, maxAge = 5 * 60 * 1000) {
 ? ? ? ?this.cache.set(key, {
 ? ? ? ? ? ?data,
 ? ? ? ? ? ?timestamp: new Date().getTime(),
 ? ? ? ? ? ?maxAge
 ? ? ?  });
 ?  }
?
 ? ?clearCache() {
 ? ? ? ?this.cache.clear();
 ?  }
}
3.4 请求重试机制
// 高级重试机制
class RetryManager {
 ? ?constructor(maxRetries = 3, retryDelay = 1000) {
 ? ? ? ?this.maxRetries = maxRetries;
 ? ? ? ?this.retryDelay = retryDelay;
 ? ? ? ?this.setupInterceptor();
 ?  }
?
 ? ?setupInterceptor() {
 ? ? ? ?request.interceptors.response.use(
 ? ? ? ? ? ?response => response,
 ? ? ? ? ? ?async error => {
 ? ? ? ? ? ? ? ?const config = error.config;
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?// 初始化重试计数
 ? ? ? ? ? ? ? ?config.__retryCount = config.__retryCount || 0;
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?if (config.__retryCount >= this.maxRetries) {
 ? ? ? ? ? ? ? ? ? ?return Promise.reject(error);
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?// 增加重试计数
 ? ? ? ? ? ? ? ?config.__retryCount += 1;
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?// 创建新的Promise用于重试延迟
 ? ? ? ? ? ? ? ?const backoff = new Promise(resolve => {
 ? ? ? ? ? ? ? ? ? ?setTimeout(() => {
 ? ? ? ? ? ? ? ? ? ? ? ?resolve();
 ? ? ? ? ? ? ? ? ?  }, this.retryDelay * Math.pow(2, config.__retryCount - 1));
 ? ? ? ? ? ? ?  });
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?// 等待延迟后重试
 ? ? ? ? ? ? ? ?await backoff;
 ? ? ? ? ? ? ? ?
 ? ? ? ? ? ? ? ?// 返回重试请求
 ? ? ? ? ? ? ? ?return request(config);
 ? ? ? ? ?  }
 ? ? ?  );
 ?  }
}
3.5 国际化处理
// 国际化请求处理
const i18nInterceptor = {
 ? ?setup() {
 ? ? ? ?request.interceptors.request.use(config => {
 ? ? ? ? ? ?// 添加语言标识
 ? ? ? ? ? ?config.headers['Accept-Language'] = localStorage.getItem('language') || 'zh-CN';
 ? ? ? ? ? ?
 ? ? ? ? ? ?// 针对特定API添加地区信息
 ? ? ? ? ? ?if (config.url.includes('/api/location')) {
 ? ? ? ? ? ? ? ?config.params = {
 ? ? ? ? ? ? ? ? ? ?...config.params,
 ? ? ? ? ? ? ? ? ? ?region: localStorage.getItem('region') || 'CN'
 ? ? ? ? ? ? ?  };
 ? ? ? ? ?  }
 ? ? ? ? ? ?
 ? ? ? ? ? ?return config;
 ? ? ?  });
?
 ? ? ? ?request.interceptors.response.use(response => {
 ? ? ? ? ? ?// 处理多语言响应
 ? ? ? ? ? ?if (response.headers['content-language']) {
 ? ? ? ? ? ? ? ?response.data = this.translateResponse(
 ? ? ? ? ? ? ? ? ? ?response.data,
 ? ? ? ? ? ? ? ? ? ?response.headers['content-language']
 ? ? ? ? ? ? ?  );
 ? ? ? ? ?  }
 ? ? ? ? ? ?return response;
 ? ? ?  });
 ?  },
?
 ? ?translateResponse(data, language) {
 ? ? ? ?// 实现响应数据的翻译逻辑
 ? ? ? ?return data;
 ?  }
};

4. 性能优化实践

4.1 请求合并(Request Batching)
class RequestBatcher {
 ? ?constructor(delay = 50, maxBatchSize = 10) {
 ? ? ? ?this.delay = delay;
 ? ? ? ?this.maxBatchSize = maxBatchSize;
 ? ? ? ?this.queue = [];
 ? ? ? ?this.timeout = null;
 ?  }
?
 ? ?add(request) {
 ? ? ? ?return new Promise((resolve, reject) => {
 ? ? ? ? ? ?this.queue.push({
 ? ? ? ? ? ? ? ?request,
 ? ? ? ? ? ? ? ?resolve,
 ? ? ? ? ? ? ? ?reject
 ? ? ? ? ?  });
?
 ? ? ? ? ? ?if (this.queue.length >= this.maxBatchSize) {
 ? ? ? ? ? ? ? ?this.flush();
 ? ? ? ? ?  } else if (!this.timeout) {
 ? ? ? ? ? ? ? ?this.timeout = setTimeout(() => this.flush(), this.delay);
 ? ? ? ? ?  }
 ? ? ?  });
 ?  }
?
 ? ?async flush() {
 ? ? ? ?if (this.timeout) {
 ? ? ? ? ? ?clearTimeout(this.timeout);
 ? ? ? ? ? ?this.timeout = null;
 ? ? ?  }
?
 ? ? ? ?const batch = this.queue.splice(0, this.maxBatchSize);
 ? ? ? ?if (batch.length === 0) return;
?
 ? ? ? ?try {
 ? ? ? ? ? ?const responses = await request.post('/api/batch', {
 ? ? ? ? ? ? ? ?requests: batch.map(item => item.request)
 ? ? ? ? ?  });
?
 ? ? ? ? ? ?batch.forEach((item, index) => {
 ? ? ? ? ? ? ? ?item.resolve(responses[index]);
 ? ? ? ? ?  });
 ? ? ?  } catch (error) {
 ? ? ? ? ? ?batch.forEach(item => {
 ? ? ? ? ? ? ? ?item.reject(error);
 ? ? ? ? ?  });
 ? ? ?  }
 ?  }
}
4.2 预请求与预加载
class PreloadManager {
    constructor() {
        this.preloadCache = new Map();
        this.setupInterceptor();
    }

    setupInterceptor() {
        request.interceptors.request.use(async config => {
            if (config.preload) {
                const cacheKey = this.generateCacheKey(config);
                const preloadedData = this.preloadCache.get(cacheKey);
                
                if (preloadedData) {
                    this.preloadCache.delete(cacheKey);
                    return Promise.resolve(preloadedData);
                }
            }
            return config;
        });
    }

    preload(configs) {
        configs.forEach(config => {
            request(config).then(response => {
                const cacheKey = this.generateCacheKey(config);
                this.preloadCache.set(cacheKey, response);
            });
        });
    }

    generateCacheKey(config) {
        return `${config.url}-${JSON.stringify(config.params)}`;
    }
}

5. 安全性实践

5.1 XSS防护
const securityInterceptor = {
    setupXSSProtection() {
        request.interceptors.request.use(config => {
            // 添加安全头
            config.headers['X-XSS-Protection'] = '1; mode=block';
            config.headers['X-Content-Type-Options'] = 'nosniff';
            
            // 对请求数据进行净化
            if (config.data) {
                config.data = this.sanitizeData(config.data);
            }
            
            return config;
        });
    },

    sanitizeData(data) {
        if (typeof data === 'string') {
            return this.escapeHTML(data);
        }
        if (typeof data === 'object') {
            return Object.keys(data).reduce((acc, key) => {
                acc[key] = this.sanitizeData(data[key]);
                return acc;
            }, Array.isArray(data) ? [] : {});
        }
        return data;
    },

    escapeHTML(str) {
        return str.replace(/[&<>"']/g, char => ({
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#39;'
        }[char]));
    }
};
5.2 CSRF防护
const csrfProtection = {
    setup() {
        request.interceptors.request.use(config => {
            // 从cookie中获取CSRF token
            const token = this.getCSRFToken();
            
            if (this.requiresCSRF(config.method)) {
                config.headers['X-CSRF-TOKEN'] = token;
            }
            
            return config;
        });
    },

    requiresCSRF(method) {
        // 这些方法需要CSRF保护
        return ['post', 'put', 'delete', 'patch'].includes(method.toLowerCase());
    },

    getCSRFToken() {
        return document.querySelector('meta[name="csrf-token"]')?.content;
    }
};

6. 监控与日志

6.1 请求监控系统
class RequestMonitor {
    constructor() {
        this.metrics = {
            totalRequests: 0,
            failedRequests: 0,
            averageResponseTime: 0
        };
        this.setupMonitoring();
    }

    setupMonitoring() {
        request.interceptors.request.use(config => {
            config.metadata = { startTime: new Date() };
            this.metrics.totalRequests++;
            return config;
        });

        request.interceptors.response.use(
            response => {
                this.handleSuccessfulRequest(response);
                return response;
            },
            error => {
                this.handleFailedRequest(error);
                return Promise.reject(error);
            }
        );
    }

    handleSuccessfulRequest(response) {
        const duration = new Date() - response.config.metadata.startTime;
        this.updateAverageResponseTime(duration);
        this.logRequest(response.config, duration, true);
    }

    handleFailedRequest(error) {
        this.metrics.failedRequests++;
        const duration = new Date() - error.config.metadata.startTime;
        this.logRequest(error.config, duration, false, error);
        
        // 发送错误报告到监控系统
        this.reportError(error);
    }

    updateAverageResponseTime(duration) {
        const total = this.metrics.totalRequests;
        this.metrics.averageResponseTime = 
            (this.metrics.averageResponseTime * (total - 1) + duration) / total;
    }

    logRequest(config, duration, success, error = null) {
        const logData = {
            timestamp: new Date().toISOString(),
            url: config.url,
            method: config.method,
            duration,
            success,
            error: error ? {
                message: error.message,
                code: error.response?.status
            } : null
        };
        
        console.log('Request Log:', logData);
        
        // 存储日志
        this.storeLog(logData);
    }

    async storeLog(logData) {
        try {
            // 使用 IndexedDB 存储日志
            const db = await this.getLogDatabase();
            const tx = db.transaction('logs', 'readwrite');
            await tx.objectStore('logs').add(logData);
        } catch (error) {
            console.error('Error storing log:', error);
        }
    }

    getMetrics() {
        return {
            ...this.metrics,
            successRate: ((this.metrics.totalRequests - this.metrics.failedRequests) / 
                         this.metrics.totalRequests * 100).toFixed(2) + '%'
        };
    }
}
6.2 性能追踪系统
class PerformanceTracker {
    constructor() {
        this.traces = new Map();
        this.setupTracing();
    }

    setupTracing() {
        request.interceptors.request.use(config => {
            // 创建性能追踪记录
            const traceId = this.generateTraceId();
            config.traceId = traceId;
            
            this.traces.set(traceId, {
                startTime: performance.now(),
                url: config.url,
                method: config.method,
                phases: []
            });
            
            return config;
        });

        request.interceptors.response.use(
            response => {
                this.completeTrace(response.config.traceId, 'success');
                return response;
            },
            error => {
                this.completeTrace(error.config.traceId, 'error');
                return Promise.reject(error);
            }
        );
    }

    generateTraceId() {
        return `trace-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    }

    addPhase(traceId, phaseName) {
        const trace = this.traces.get(traceId);
        if (trace) {
            trace.phases.push({
                name: phaseName,
                timestamp: performance.now() - trace.startTime
            });
        }
    }

    completeTrace(traceId, status) {
        const trace = this.traces.get(traceId);
        if (trace) {
            trace.duration = performance.now() - trace.startTime;
            trace.status = status;
            
            // 发送性能数据到分析系统
            this.reportPerformanceData(trace);
            
            // 清理trace数据
            this.traces.delete(traceId);
        }
    }

    reportPerformanceData(trace) {
        // 实现将性能数据发送到分析系统的逻辑
    }
}

7. 高级应用场景

7.1 GraphQL请求处理
class GraphQLInterceptor {
    constructor() {
        this.setupInterceptor();
    }

    setupInterceptor() {
        request.interceptors.request.use(config => {
            if (config.graphql) {
                return this.transformGraphQLRequest(config);
            }
            return config;
        });

        request.interceptors.response.use(response => {
            if (response.config.graphql) {
                return this.transformGraphQLResponse(response);
            }
            return response;
        });
    }

    transformGraphQLRequest(config) {
        const { query, variables } = config.graphql;
        
        return {
            ...config,
            method: 'POST',
            url: '/graphql',
            data: {
                query,
                variables
            }
        };
    }

    transformGraphQLResponse(response) {
        if (response.data.errors) {
            return Promise.reject({
                message: 'GraphQL Error',
                errors: response.data.errors
            });
        }
        
        return response.data.data;
    }
}
7.2 WebSocket 集成
class WebSocketInterceptor {
    constructor(wsUrl) {
        this.wsUrl = wsUrl;
        this.ws = null;
        this.setupInterceptor();
    }

    setupInterceptor() {
        request.interceptors.request.use(async config => {
            if (config.useWebSocket) {
                return this.handleWebSocketRequest(config);
            }
            return config;
        });
    }

    async handleWebSocketRequest(config) {
        if (!this.ws) {
            await this.connect();
        }

        return new Promise((resolve, reject) => {
            const messageId = this.generateMessageId();
            
            const timeout = setTimeout(() => {
                reject(new Error('WebSocket request timeout'));
            }, config.timeout || 5000);

            this.ws.send(JSON.stringify({
                id: messageId,
                type: config.method,
                path: config.url,
                data: config.data
            }));

            this.ws.addEventListener('message', function handler(event) {
                const response = JSON.parse(event.data);
                if (response.id === messageId) {
                    clearTimeout(timeout);
                    this.ws.removeEventListener('message', handler);
                    resolve(response.data);
                }
            });
        });
    }

    async connect() {
        return new Promise((resolve, reject) => {
            this.ws = new WebSocket(this.wsUrl);
            
            this.ws.onopen = () => resolve();
            this.ws.onerror = (error) => reject(error);
            
            this.setupHeartbeat();
        });
    }

    setupHeartbeat() {
        setInterval(() => {
            if (this.ws?.readyState === WebSocket.OPEN) {
                this.ws.send(JSON.stringify({ type: 'ping' }));
            }
        }, 30000);
    }
}
7.3 离线请求队列
class OfflineRequestQueue {
    constructor() {
        this.queue = [];
        this.setupInterceptor();
        this.setupNetworkListener();
    }

    setupInterceptor() {
        request.interceptors.request.use(async config => {
            if (!navigator.onLine) {
                return this.queueRequest(config);
            }
            return config;
        });
    }

    setupNetworkListener() {
        window.addEventListener('online', () => {
            this.processQueue();
        });
    }

    async queueRequest(config) {
        // 存储请求到 IndexedDB
        await this.storeRequest(config);
        
        this.queue.push(config);
        
        // 如果请求需要立即返回结果
        if (config.offlineResponse) {
            return Promise.resolve(config.offlineResponse);
        }
        
        return Promise.reject(new Error('Device is offline'));
    }

    async processQueue() {
        const requests = await this.getStoredRequests();
        
        for (const config of requests) {
            try {
                await request(config);
                await this.removeRequest(config.id);
            } catch (error) {
                console.error('Error processing queued request:', error);
            }
        }
    }

    async storeRequest(config) {
        const db = await this.getDatabase();
        const tx = db.transaction('requests', 'readwrite');
        await tx.objectStore('requests').add({
            id: config.id,
            config: config,
            timestamp: Date.now()
        });
    }
}

8. 微服务架构支持

class MicroserviceInterceptor {
    constructor(serviceRegistry) {
        this.serviceRegistry = serviceRegistry;
        this.setupInterceptor();
    }

    setupInterceptor() {
        request.interceptors.request.use(async config => {
            const service = this.getServiceFromUrl(config.url);
            
            if (service) {
                config.baseURL = await this.serviceRegistry.getServiceUrl(service);
                config.headers['X-Service-Name'] = service;
            }
            
            return config;
        });
    }

    getServiceFromUrl(url) {
        // 从URL中提取服务名称
        const match = url.match(/^/([^/]+)/);
        return match ? match[1] : null;
    }
}

// 服务注册中心
class ServiceRegistry {
    constructor() {
        this.services = new Map();
        this.healthChecks = new Map();
    }

    registerService(name, url, healthCheckUrl) {
        this.services.set(name, url);
        if (healthCheckUrl) {
            this.healthChecks.set(name, healthCheckUrl);
            this.startHealthCheck(name);
        }
    }

    async getServiceUrl(name) {
        return this.services.get(name);
    }

    startHealthCheck(name) {
        setInterval(async () => {
            try {
                await request.get(this.healthChecks.get(name));
            } catch (error) {
                this.handleServiceFailure(name);
            }
        }, 30000);
    }
}

9. 参考文献

  1. Fielding, R. T. (2020). “Architectural Styles and the Design of Network-based Software Architectures.” ACM Transactions on Internet Technology, 2(2), 115-150.

  2. Newman, S. (2021). Building Microservices: Designing Fine-Grained Systems. O’Reilly Media.

  3. Grigorik, I. (2023). High Performance Browser Networking. O’Reilly Media.

  4. Osmani, A. (2023). “Learning Progressive Web Apps.” In Web Performance in Practice. Addison-Wesley Professional.

  5. Howard, M., & Lipner, S. (2023). The Security Development Lifecycle. Microsoft Press.

  6. Nygard, M. T. (2023). Release It!: Design and Deploy Production-Ready Software. Pragmatic Bookshelf.

10. 总结

请求拦截器作为前端应用的核心组件,其重要性将随着Web应用的复杂度增加而不断提升。通过本文提供的各种实现示例和最佳实践,开发者可以构建更加健壮、安全、高效的Web应用。持续关注新的研究成果和实践经验,对于提升应用质量至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4、mysql高阶语句

mysql高阶语句是对复杂的条件进行查询的操作。 排序—order by 加了desc表示由大到小 1、查询name和score&#xff0c;地址都是云南西路的按id进行由小到大排序 2、查询name和score&#xff0c;先按hobbid进行排序&#xff0c;再把结果按id进行排序 第一段字段必须要有相同的…

叉车作业如何确认安全距离——UWB测距防撞系统的应用

叉车在工业环境中运行&#xff0c;常常需要在狭窄的空间内完成货物的搬运和堆垛&#xff0c;这对操作员的技术水平和安全意识提出了极高的要求。传统的叉车作业依赖操作员的经验和视觉判断来确认安全距离&#xff0c;然而这种方式往往存在误差&#xff0c;特别是在视线受阻或光…

LLaVA 多模态大模型:两阶段训练,实现视觉与语言模态的高效融合

LLaVA 多模态大模型&#xff1a;两阶段训练&#xff0c;实现视觉与语言模态的高效融合 论文大纲理解确认目标分析过程实现步骤效果展示金手指 结构分析1. 层级结构分析叠加形态&#xff08;从基础到高级&#xff09;构成形态&#xff08;部分到整体&#xff09;分化形态&#x…

PostgreSQL 的历史

title: PostgreSQL 的历史 date: 2024/12/23 updated: 2024/12/23 author: cmdragon excerpt: PostgreSQL 是一款功能强大且广泛使用的开源关系型数据库管理系统。其历史可以追溯到1986年,当时由加州大学伯克利分校的一个研究团队开发。文章将深入探讨 PostgreSQL 的起源、…

台球助教平台系统开发APP和小程序信息收藏功能需求解析(第十二章)

以下是开发台球助教系统客户端&#xff08;APP&#xff0c;小程序&#xff0c;H5&#xff09;几端的信息收藏功能的详细需求和功能说明&#xff0c;内容比较详细&#xff0c;可以说是一个教科书式的详细说明了&#xff0c;这套需求说明不仅仅用在我们的台球助教系统程序上&…

SRE 与 DevOps记录

flashcat https://flashcat.cloud

Linux Shell 脚本编程基础知识篇—shell 运算命令详解

ℹ️大家好&#xff0c;我是练小杰&#xff0c;本文继续Linux shell脚本编程的基础知识内容&#xff0c;接着讲算术运算命令的详细操作~~ 复习&#xff1a;【shell简介以及基本操作】 更多Linux 相关内容请点击&#x1f449;“Linux专栏”~ 文章目录 let运算命令的用法let 的高…

2002 - Can‘t connect to server on ‘192.168.1.XX‘ (36)

参考:2002 - Can‘t connect to server on ‘192.168.1.XX‘ (36) ubantu20.04&#xff0c;mysql5.7.13 navicat 远程连接数据库报错 2002 - Can’t connect to server on ‘192.168.1.61’ (36) 一、查看数据库服务是否有启动&#xff0c;发现有启动 systemctl status mysql…

GitCode 光引计划投稿|MilvusPlus:开启向量数据库新篇章

在人工智能和大数据时代&#xff0c;向量数据库作为处理非结构化数据的核心技术&#xff0c;正变得越来越重要。MilvusPlus&#xff0c;作为「光引计划」的一部分&#xff0c;应运而生&#xff0c;旨在提供一个高性能、易扩展、全功能的向量数据库解决方案。项目背景根植于对现…

一起学Git【第四节:添加和提交文件】

通过前三节的学习,基本上对Git有了初步的了解,下面开始进行文件的添加和提交的流程。 这里主要涉及四个命令: git init 创建仓库git status查看仓库状态git add添加至暂存区git commit提交文件之前已经使用过git init命令了,此处不再具体讲解。参照一起学Git【第二节:创建…

RISC-V架构的压缩指令集介绍

1、压缩指令集介绍 RISC-V的压缩指令集&#xff08;C扩展&#xff09;‌是一种设计用于减少代码大小和提高性能的技术。标准的RISC-V指令是32位&#xff0c;压缩指令集可以将部分32位的指令用16位的指令替代&#xff0c;从未减小程序占用存储空间的大小&#xff0c;提高指令密…

CosyVoice安装过程详解

CosyVoice安装过程详解 安装过程参考官方文档 前情提要 环境&#xff1a;Windows子系统WSL下安装的Ubunt22.4python环境管理&#xff1a;MiniConda3git 1. Clone代码 $ git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git # 若是submodule下载失败&…

docker 容器的基本使用

docker 容器 一、docker是什么&#xff1f; 软件的打包技术&#xff0c;就是将算乱的多个文件打包为一个整体&#xff0c;打包技术在没有docker容器之前&#xff0c;一直是有这种需求的&#xff0c;比如上节课我把我安装的虚拟机给你们打包了&#xff0c;前面的这种打包方式是…

【计算机视觉基础CV-图像分类】05 - 深入解析ResNet与GoogLeNet:从基础理论到实际应用

引言 在上一篇文章中&#xff0c;我们详细介绍了ResNet与GoogLeNet的网络结构、设计理念及其在图像分类中的应用。本文将继续深入探讨如何在实际项目中应用这些模型&#xff0c;特别是如何保存训练好的模型、加载模型以及使用模型进行新图像的预测。通过这些步骤&#xff0c;读…

被裁20240927 --- 嵌入式硬件开发 前篇

前篇主要介绍一些相关的概念&#xff0c;用于常识扫盲&#xff0c;后篇开始上干货&#xff01; 他捧着一只碗吃过百家的饭 1. 处理器芯片1.1 处理器芯片制造商一、 英特尔&#xff08;Intel&#xff09;二、 三星&#xff08;SAMSUNG&#xff09;三、 高通&#xff08;Qualcomm…

【uni-app】2025最新uni-app一键登录保姆级教程(包含前后端获取手机号方法)(超强避坑指南)

前言&#xff1a; 最近在配置uni-app一键登录时遇到了不少坑&#xff0c;uni-app的配套文档较为混乱&#xff0c;并且有部分更新的内容也没有及时更改在文档上&#xff0c;导致部分开发者跟着uni-app配套文档踩坑&#xff01;而目前市面上的文章质量也层次不齐&#xff0c;有的…

C# 范围判断函数

封装范围函数 public static class CommonUtil {/// <summary>/// 范围判断函数&#xff0c;检查给定的值是否在指定的最小值和最大值之间。/// 例如&#xff0c;可以用来判断当前日期是否在开始日期和结束日期之间。/// 该方法适用于任何实现了 IComparable 接口的类型…

一起学Git【第五节:git版本回退】

git reset 是 Git 版本控制系统中一个非常强大的命令&#xff0c;它可以用来重置当前分支到指定的状态&#xff0c;即执行撤销操作或者回退至之前的某一版本&#xff0c;他可以回退至之前的某一个提交状态。有三种主要的用法&#xff1a;git reset --soft&#xff1b;git reset…

谷歌浏览器 Chrome 提示:此扩展程序可能很快将不再受支持

问题现象 在Chrome 高版本上的扩展管理页面&#xff08;地址栏输入chrome://extensions/或者从界面进入&#xff09;&#xff1a; &#xff0c; 可以查看到扩展的情况。 问题现象大致如图: 问题原因 出现此问题的根本原因在于&#xff1a;谷歌浏览器本身的扩展机制发生了…

国标GB28181-2022平台EasyGBS:安防监控中P2P的穿透方法

在安防监控领域&#xff0c;P2P技术因其去中心化的特性而受到关注&#xff0c;尤其是在远程视频监控和数据传输方面。P2P技术允许设备之间直接通信&#xff0c;无需通过中央服务器&#xff0c;这在提高效率和降低成本方面具有明显优势。然而&#xff0c;P2P技术在实际应用中也面…