手动封装 ajax

49 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

  • 我们在使用js的时候,发送请求可以使用两种原生提供的方式,fetch 或 xhr,我们使用的所有包库也都是在这基础之上进行的封装。
  • 下面我们来自己封装一下 xhr, 虽然不如我们使用的 包库健壮,但是从中我们也能够学习到这种封装的思维,错误处理的逻辑等。

这个方法是可以直接使用的,我们使用 pAjax 方法,接受的参数 就是我们接口定义的 ajaxParams, url 为必填,其他项为选填,默认 请求方式为 get,我自己写项目的时候,也使用过这个方法,但如果对接口有更多的 前置 或后置处理,可能需要去使用 包库 附带的请求拦截器了,这里并没有做请求拦截器的封装。

type methodType = 'GET' | 'POST';
type dataEnum = 'string' | 'json';

export interface ajaxParams {
    url:string,
    method?: methodType,
    async?:true,
    data?: any,
    headers?:Record<string|number|symbol,string>,
    dataType?:dataEnum,
    success?:(res:any) => any,
    error?:(res:any) => any
}


function queryStringify(obj:any) {
    var str = '';
    for (var k in obj) {
        str += k + '=' + obj[k] + '&';
    }
    return str.slice(0, -1);
}

function ajax(options:ajaxParams) {
    if (Object.prototype.toString.call(options) !== '[object Object]') {
        throw new Error('"options"需要传递一个 Object 类型数据');
    }
    const { url, method, async, data, headers, dataType, success, error } =
        options;
    if (!(method === undefined || /^(get|post)$/i.test(method))) {
        throw new Error('只接受 GET 和 POST 请求');
    }
    if (!(async === undefined || typeof async === 'boolean')) {
        throw new Error('"async" 需要传递一个布尔值');
    }
    if (
        !(
            data === undefined ||
            typeof data === 'string' ||
            Object.prototype.toString.call(data) === '[object Object]'
        )
    ) {
        throw new Error('"data"需要传递一个 String 或者 Object 类型数据');
    }
    if (
        !(
            headers === undefined ||
            Object.prototype.toString.call(headers) === '[object Object]'
        )
    ) {
        throw new Error('"headers" 需要传递一个 Object 数据类型');
    }
    if (!(dataType === undefined || /^(string|json)$/i.test(dataType))) {
        throw new Error('"dataType" 需要传递一个 "string" 或 "json"');
    }
    if (!(success === undefined || typeof success === 'function')) {
        throw new Error('"success" 需要传递一个 Function 数据类型');
    }
    if (!(error === undefined || typeof error === 'function')) {
        throw new Error('"error" 需要传递一个 Function 数据类型');
    }
    const _default = {
        url: url,
        method: method || 'GET',
        async: async ?? false,
        data: data || '',
        headers: {
            'content-type': 'application/x-www-form-urlencoded;charset=utf-8;',
            ...headers,
        } as Record<string,any>,
        dataType: dataType || 'json',
        success: success || function () {},
        error: error || function () {},
    };
    //data 如果是对象数据类型,转换成查询字符串
    if (typeof data === 'object') _default.data = queryStringify(data);
    //如果是get请求,并且有参数,直接组装url信息
    if (/^get$/i.test(_default.method) && data)
        _default.url += '?' + _default.data;
    //开始请求操作
    const xhr = new XMLHttpRequest();
    xhr.open(_default.method, _default.url, _default.async);
    xhr.onload = function () {
        if (_default.dataType === 'string')
            return _default.success(xhr.responseText);
        try {
            let result = JSON.parse(xhr.responseText);
            const { data } = result
            console.log('使用自己封装的方法请求',data);
            
            _default.success(data);
        } catch (err) {
            _default.error(
                '解析失败 ! 因为后端返回的结果不是 json 格式字符串, 请查证后再试 !!!'
            );
        }
    };
    for (let k in _default.headers)
        xhr.setRequestHeader(k, _default.headers[k]);
    /^get$/i.test(_default.method) ? xhr.send() : xhr.send(_default.data);
}

/**
 * 
 * @param (ajaxParams)  options 
 * @returns  Promise
 */
export  function pAjax(options:ajaxParams):Promise<any>  {
    return new Promise((resolve, reject) => {
        ajax({
            url: options.url,
            data: options.data,
            async: options.async,
            method: options.method,
            headers: options.headers,
            dataType: options.dataType,
            success(res: any) {
                resolve(res);
            },
            error(err: any) {
                reject(err);
            },
        });
    });
}
export default pAjax