濮阳市浔绾网

AJAX乱码与异步同步以及封装jQuery库实现步骤详解

2026-04-14 15:19:01 浏览次数:1
详细信息

一、AJAX 乱码问题

1.1 原因分析

AJAX 乱码通常由以下原因引起:

字符编码不一致

数据传输过程编码丢失

1.2 解决方案

// 1. 统一使用UTF-8编码
// 服务端设置(以Java为例)
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");

// 2. AJAX请求设置请求头
$.ajax({
    url: 'api/data',
    type: 'POST',
    contentType: 'application/x-www-form-urlencoded;charset=UTF-8',
    data: { name: '张三' },
    success: function(response) {
        console.log(response);
    }
});

// 3. 处理特殊字符
function encodeData(data) {
    return encodeURIComponent(JSON.stringify(data));
}

二、AJAX 异步与同步

2.1 异步模式(默认)

// 异步示例
console.log('1. 开始请求');
$.ajax({
    url: 'api/data',
    async: true, // 默认true
    success: function() {
        console.log('3. 请求完成');
    }
});
console.log('2. 继续执行');

// 输出顺序:1 → 2 → 3

2.2 同步模式

// 同步示例 - 会阻塞后续代码执行
console.log('1. 开始请求');
$.ajax({
    url: 'api/data',
    async: false, // 设置为同步
    success: function() {
        console.log('2. 请求完成');
    }
});
console.log('3. 继续执行');

// 输出顺序:1 → 2 → 3(会等待请求完成)

2.3 使用建议

// 使用Promise封装
function ajaxRequest(url) {
    return new Promise((resolve, reject) => {
        $.ajax({
            url: url,
            success: resolve,
            error: reject
        });
    });
}

// async/await使用
async function fetchData() {
    try {
        const data = await ajaxRequest('api/data');
        console.log('数据:', data);
    } catch (error) {
        console.error('请求失败:', error);
    }
}

三、jQuery AJAX 封装实现

3.1 基础封装

// 简单封装示例
const MyAjax = {
    // 默认配置
    defaults: {
        baseURL: '',
        timeout: 10000,
        headers: {
            'Content-Type': 'application/json'
        }
    },

    // 合并配置
    mergeConfig(config) {
        return { ...this.defaults, ...config };
    },

    // 请求方法
    request(config) {
        const mergedConfig = this.mergeConfig(config);

        return new Promise((resolve, reject) => {
            $.ajax({
                url: mergedConfig.baseURL + mergedConfig.url,
                type: mergedConfig.method || 'GET',
                data: mergedConfig.data,
                headers: mergedConfig.headers,
                timeout: mergedConfig.timeout,
                dataType: mergedConfig.dataType || 'json',

                success: function(response) {
                    resolve(response);
                },

                error: function(xhr, status, error) {
                    reject({
                        status: xhr.status,
                        statusText: xhr.statusText,
                        message: error
                    });
                },

                // 请求完成回调
                complete: function() {
                    console.log('请求完成');
                }
            });
        });
    },

    // 快捷方法
    get(url, params = {}) {
        return this.request({
            url: url,
            method: 'GET',
            data: params
        });
    },

    post(url, data = {}) {
        return this.request({
            url: url,
            method: 'POST',
            data: JSON.stringify(data)
        });
    },

    put(url, data = {}) {
        return this.request({
            url: url,
            method: 'PUT',
            data: JSON.stringify(data)
        });
    },

    delete(url) {
        return this.request({
            url: url,
            method: 'DELETE'
        });
    }
};

3.2 高级封装(支持拦截器)

class AjaxLibrary {
    constructor() {
        this.defaults = {
            baseURL: '',
            timeout: 10000,
            headers: {},
            withCredentials: false
        };

        // 拦截器
        this.interceptors = {
            request: [],
            response: []
        };
    }

    // 添加请求拦截器
    useRequestInterceptor(interceptor) {
        this.interceptors.request.push(interceptor);
        return this;
    }

    // 添加响应拦截器
    useResponseInterceptor(interceptor) {
        this.interceptors.response.push(interceptor);
        return this;
    }

    // 执行拦截器链
    async runInterceptors(chain, initialValue) {
        let value = initialValue;

        for (const interceptor of chain) {
            value = await interceptor(value);
        }

        return value;
    }

    // 核心请求方法
    async request(config) {
        // 合并配置
        const mergedConfig = { ...this.defaults, ...config };

        // 请求拦截
        try {
            mergedConfig = await this.runInterceptors(
                this.interceptors.request,
                mergedConfig
            );
        } catch (error) {
            return Promise.reject(error);
        }

        // 发送请求
        return new Promise((resolve, reject) => {
            $.ajax({
                url: mergedConfig.baseURL + mergedConfig.url,
                type: mergedConfig.method || 'GET',
                data: mergedConfig.data,
                headers: mergedConfig.headers,
                timeout: mergedConfig.timeout,
                dataType: mergedConfig.dataType || 'json',
                xhrFields: {
                    withCredentials: mergedConfig.withCredentials
                },

                beforeSend: function(xhr) {
                    // 可以在这里添加全局loading
                    console.log('开始发送请求');
                },

                success: async (response, status, xhr) => {
                    try {
                        // 响应拦截
                        const processedResponse = await this.runInterceptors(
                            this.interceptors.response,
                            { data: response, status: xhr.status, headers: xhr.getAllResponseHeaders() }
                        );
                        resolve(processedResponse);
                    } catch (error) {
                        reject(error);
                    }
                },

                error: function(xhr, status, error) {
                    const err = {
                        status: xhr.status,
                        statusText: xhr.statusText,
                        message: error,
                        response: xhr.responseText
                    };
                    reject(err);
                },

                complete: function() {
                    // 可以在这里隐藏全局loading
                    console.log('请求完成');
                }
            });
        });
    }

    // 创建实例方法
    create(instanceConfig) {
        const instance = new AjaxLibrary();
        instance.defaults = { ...this.defaults, ...instanceConfig };
        return instance;
    }
}

// 使用示例
const api = new AjaxLibrary();

// 设置全局配置
api.defaults.baseURL = 'https://api.example.com';
api.defaults.headers['Authorization'] = 'Bearer token';

// 添加拦截器
api.useRequestInterceptor((config) => {
    // 添加时间戳防止缓存
    if (config.method === 'GET') {
        config.url += (config.url.includes('?') ? '&' : '?') + '_t=' + Date.now();
    }
    return config;
});

api.useResponseInterceptor((response) => {
    // 统一处理响应格式
    if (response.status === 200) {
        return response.data;
    } else {
        throw new Error('请求失败');
    }
});

// 使用快捷方法
['get', 'post', 'put', 'delete', 'patch'].forEach(method => {
    AjaxLibrary.prototype[method] = function(url, data, config) {
        return this.request({
            url,
            method: method.toUpperCase(),
            data,
            ...config
        });
    };
});

// 发送请求
api.get('/users')
    .then(data => console.log(data))
    .catch(error => console.error(error));

3.3 错误处理和重试机制

// 扩展错误处理和重试
class EnhancedAjax extends AjaxLibrary {
    constructor(maxRetries = 3) {
        super();
        this.maxRetries = maxRetries;
    }

    async requestWithRetry(config, retryCount = 0) {
        try {
            return await super.request(config);
        } catch (error) {
            // 特定错误码重试
            const shouldRetry = this.shouldRetry(error, retryCount);

            if (shouldRetry) {
                console.log(`第${retryCount + 1}次重试`);
                return this.requestWithRetry(config, retryCount + 1);
            }

            throw error;
        }
    }

    shouldRetry(error, retryCount) {
        // 网络错误或5xx错误重试
        const retryCodes = [0, 500, 502, 503, 504];
        return retryCount < this.maxRetries && 
               (retryCodes.includes(error.status) || !navigator.onLine);
    }

    // 并发请求控制
    async all(requests, maxConcurrent = 5) {
        const results = [];
        const executing = [];

        for (const request of requests) {
            const promise = request().then(result => {
                results.push(result);
                executing.splice(executing.indexOf(promise), 1);
                return result;
            });

            executing.push(promise);

            if (executing.length >= maxConcurrent) {
                await Promise.race(executing);
            }
        }

        await Promise.all(executing);
        return results;
    }
}

四、完整使用示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AJAX封装示例</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <div id="app">
        <button onclick="getUsers()">获取用户</button>
        <button onclick="createUser()">创建用户</button>
        <div id="result"></div>
    </div>

    <script>
        // 创建API实例
        const api = new EnhancedAjax(3);

        // 配置
        api.defaults.baseURL = 'https://jsonplaceholder.typicode.com';
        api.defaults.headers['Content-Type'] = 'application/json';

        // 请求拦截器 - 添加认证token
        api.useRequestInterceptor((config) => {
            const token = localStorage.getItem('token');
            if (token) {
                config.headers['Authorization'] = `Bearer ${token}`;
            }
            return config;
        });

        // 响应拦截器 - 统一处理错误
        api.useResponseInterceptor((response) => {
            if (response.status >= 400) {
                throw new Error(`HTTP错误: ${response.status}`);
            }
            return response.data;
        });

        // 业务函数
        async function getUsers() {
            try {
                const users = await api.get('/users');
                document.getElementById('result').innerHTML = 
                    JSON.stringify(users, null, 2);
            } catch (error) {
                console.error('获取用户失败:', error);
                document.getElementById('result').innerHTML = 
                    `错误: ${error.message}`;
            }
        }

        async function createUser() {
            const newUser = {
                name: '张三',
                email: 'zhangsan@example.com'
            };

            try {
                const result = await api.post('/users', newUser);
                alert(`创建成功! ID: ${result.id}`);
            } catch (error) {
                console.error('创建用户失败:', error);
            }
        }

        // 并发请求示例
        async function fetchMultipleData() {
            const requests = [
                () => api.get('/users/1'),
                () => api.get('/posts/1'),
                () => api.get('/comments/1')
            ];

            const results = await api.all(requests, 2);
            console.log('并发结果:', results);
        }
    </script>
</body>
</html>

五、最佳实践建议

编码规范

异步处理

封装设计

性能优化

安全性

这样的封装可以提高代码复用性,统一错误处理,简化AJAX调用,并提供了良好的扩展性。

相关推荐