JavaScript网络请求怎么封装

1,089 阅读5分钟

JavaScript网络请求可以通过封装来简化代码,提高代码的可维护性和可复用性。

以下是一些常见的封装方式:

一、使用XMLHttpRequest对象进行封装

XMLHttpRequest对象是JavaScript中用于发送HTTP请求的核心对象。可以通过封装XMLHttpRequest对象来实现网络请求的封装。例如:

function request(method, url, data, callback) { 
    var xhr = new XMLHttpRequest(); 
    xhr.open(method, url, true); 
    xhr.setRequestHeader('Content-Type', 'application/json'); 
    xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()); // 添加token验证 
    xhr.onreadystatechange = function() { 
        if (xhr.readyState === 4) { 
            if (xhr.status >= 200 && xhr.status < 300) { 
                callback(null, JSON.parse(xhr.responseText)); 
            } else { 
                callback(new Error(xhr.statusText)); 
            } 
        } 
    }; 
    xhr.send(JSON.stringify(data)); 
} 

function getToken() { // 获取token的逻辑 
    return 'your_token_here'; 
} 

// 使用示例 
request('GET', '<https://api.example.com/data>', null, function(err, data) { 
    if (err) { 
        console.error(err); 
    } else { 
        console.log(data); 
    } 
}); 

在上面的示例中,我们通过xhr.setRequestHeader方法添加了一个Authorization头部,值为Bearer加上我们获取到的token。

这样,在发送请求时,服务器就会验证我们的token是否有效。如果token无效,服务器会返回401或403状态码,我们可以在onreadystatechange回调函数中处理这种情况。

二、使用第三方库进行封装

JavaScript中有很多第三方库可以用于网络请求的封装,例如Axios、Fetch、jQuery、Superagent等。这些库已经封装了网络请求的细节,可以直接调用其API来发送网络请求。

2.1 Axios网络封装

Axios是一个基于Promise的HTTP客户端,用于浏览器和Node.js。它具有以下特点:

  1. 支持浏览器和Node.js环境。
  2. 支持Promise API。
  3. 支持拦截请求和响应。
  4. 支持取消请求。
  5. 支持自动转换JSON数据。
  6. 支持客户端防御XSRF攻击。

Axios的网络封装具体细节如下:

  1. 创建实例 在使用Axios发送请求之前,需要先创建一个Axios实例。可以通过Axios.create()方法创建一个实例,也可以直接使用全局的Axios实例。
import axios from 'axios'; 
const instance = axios.create({ 
    baseURL: '<https://api.example.com>', 
    timeout: 1000, 
    headers: {'X-Custom-Header': 'foobar'} 
}); 
  1. 发送请求 Axios支持多种请求方式,包括GET、POST、PUT、DELETE等。可以通过调用实例的相应方法来发送请求。
instance.get('/user?ID=12345')
    .then(function (response) { 
        console.log(response); })
    .catch(function (error) { 
        console.log(error); 
}); 
  1. 拦截请求和响应 Axios支持拦截请求和响应,可以在请求或响应被发送或接收之前对它们进行拦截和处理。可以通过调用实例的interceptors属性来添加拦截器。
// 添加请求拦截器 
instance.interceptors.request.use(function (config) { 
    // 在发送请求之前做些什么 
    return config; 
}, function (error) { 
    // 对请求错误做些什么
    return Promise.reject(error); 
}); 

// 添加响应拦截器 
instance.interceptors.response.use(function (response) { 
    // 对响应数据做点什么 
    return response; 
}, function (error) { 
    // 对响应错误做点什么 
    return Promise.reject(error); 
}); 
  1. 取消请求 Axios支持取消请求,可以在请求还未完成时取消它。可以通过调用实例的cancelToken属性来创建一个取消令牌,然后将它传递给请求配置中的cancelToken属性。
const CancelToken = axios.CancelToken; 
const source = CancelToken.source(); 
instance.get('/user', { 
    cancelToken: source.token }).catch(function (thrown) { 
    if (axios.isCancel(thrown)) { 
        console.log('Request canceled', thrown.message); 
    } else { 
        // 处理错误 
    } 
}); 

// 取消请求 
source.cancel('Operation canceled by the user.'); 
  1. 自动转换JSON数据 Axios支持自动转换JSON数据,可以将请求和响应中的JSON数据自动转换为JavaScript对象。可以通过设置实例的transformRequest和transformResponse属性来实现自动转换。
instance.defaults.transformRequest = [function (data) { return qs.stringify(data); }]; 
instance.defaults.transformResponse = [function (data) { return JSON.parse(data); }]; 
  1. 客户端防御XSRF攻击 Axios支持客户端防御XSRF攻击,可以通过设置实例的xsrfCookieName和xsrfHeaderName属性来实现。xsrfCookieName属性用于设置存储XSRF令牌的cookie的名称,xsrfHeaderName属性用于设置发送XSRF令牌的HTTP头的名称。
instance.defaults.xsrfCookieName = 'XSRF-TOKEN'; 
instance.defaults.xsrfHeaderName = 'X-XSRF-TOKEN'; 

以下是一个基于axios的网络请求封装,包含了token验证

import axios from 'axios'; 
const instance = axios.create({ 
    baseURL: '<https://api.example.com>', timeout: 10000, 
}); 

// 请求拦截器 
instance.interceptors.request.use((config) => { 
    const token = localStorage.getItem('token'); 
    if (token) { 
        config.headers.Authorization = `Bearer ${token}`; 
    } 
    return config; 
}, (error) => { 
    return Promise.reject(error); 
}); 

// 响应拦截器 
instance.interceptors.response.use((response) => { 
    return response.data; 
}, (error) => { 
    if (error.response) { 
        switch (error.response.status) { 
            case 401: 
            // token失效,跳转到登录页 
            localStorage.removeItem('token'); 
            window.location.href = '/login'; 
            break; 
            case 404: 
            // 404错误处理 
            break; 
            default: 
            // 其他错误处理 
            break; 
        } 
    } 
    return Promise.reject(error); 
}); 

export default instance; 

在请求拦截器中,我们从localStorage中获取token,并将其添加到请求头中。在响应拦截器中,我们对token失效的情况进行了处理,将用户跳转到登录页。其他错误情况可以根据实际需求进行处理。

2.2 使用Fetch API进行封装

  1. 创建一个封装函数,接收请求的参数,如请求的URL、请求方法、请求头、请求体等。
function fetchApi(url, method, headers, body) { 
    // ... 
} 
  1. 在函数内部使用Fetch API发送请求,并返回一个Promise对象。
function fetchApi(url, method, headers, body) { 
    return fetch(url, { 
        method: method, headers: headers, body: body 
    }); 
} 
  1. 处理请求的响应,根据响应状态码判断请求是否成功,并将响应数据转换为JSON格式。
function fetchApi(url, method, headers, body) { 
    return fetch(url, { 
        method: method, headers: headers, body: body 
    }).then(response => { 
        if (!response.ok) { 
            throw new Error(response.statusText); 
        } 
        return response.json(); 
    }); 
} 
  1. 在函数中处理请求失败的情况,如网络错误或服务器错误。
function fetchApi(url, method, headers, body) { 
    return fetch(url, { 
            method: method, headers: headers, body: body 
        }).then(response => { 
        if (!response.ok) { 
            throw new Error(response.statusText); 
        } 
        return response.json(); 
    }).catch(error => { 
        console.error('Fetch API error:', error); 
    }); 
} 
  1. 最终的封装函数代码示例:
function fetchApi(url, method, headers, body) { 
    return fetch(url, { 
            method: method, headers: headers, body: body 
        }).then(response => { 
        if (!response.ok) { 
            throw new Error(response.statusText); 
        } 
        return response.json(); 
    }).catch(error => { 
        console.error('Fetch API error:', error); 
    }); 
} 

以下是一个基于Featch API的网络请求封装,包含了token验证

const API_BASE_URL = '<https://example.com/api>'; 

function fetchAPI(endpoint, options = {}) { 
    const token = localStorage.getItem('token'); 
    const headers = { 
        'Content-Type': 'application/json', 
        Authorization: `Bearer ${token}`, 
    };
    const url = `${API_BASE_URL}/${endpoint}`; 
    return fetch(url, { ...options, headers }).then((response) => { 
        if (!response.ok) { 
            throw new Error(response.statusText); 
        } 
        return response.json(); 
    }).catch((error) => { 
        console.error(error); 
    }); 
}

// 使用示例 
fetchAPI('users') .then((data) => { 
    console.log(data); 
}).catch((error) => { 
    console.error(error); 
}); 

在上面的示例中,我们定义了一个 fetchAPI 函数,它接受一个 endpoint 参数和一个可选的 options 参数。

我们使用 localStorage 获取存储在客户端的 token,并将其添加到请求头中的 Authorization 字段中。

然后,我们使用 fetch 函数发出网络请求,并在响应不是 200 OK 时抛出一个错误。

最后,我们返回响应的 JSON 数据。 在使用 fetchAPI 函数时,我们只需要传递 endpoint 参数即可。

如果需要传递其他选项,可以将它们作为第二个参数传递。例如,如果要发出 POST 请求并传递数据,可以这样做:

fetchAPI('users', { 
    method: 'POST', 
    body: JSON.stringify({ name: 'John Doe' }), 
}).then((data) => { 
    console.log(data); 
}).catch((error) => { 
    console.error(error); 
}); 

2.3 使用jQuery封装网络请求

  1. 创建一个封装网络请求的函数,例如:
function ajaxRequest(url, method, data, successCallback, errorCallback) { 
    // 网络请求代码 
} 
  1. 在函数中使用jQuery的ajax方法发送网络请求,例如:
function ajaxRequest(url, method, data, successCallback, errorCallback) { 
    $.ajax({ 
        url: url, 
        method: method, 
        data: data, 
        success: successCallback, 
        error: errorCallback 
    }); 
} 
  1. 在函数中添加参数,例如:
function ajaxRequest(url, method, data, successCallback, errorCallback, headers) { 
    $.ajax({ 
        url: url, 
        method: method, 
        data: data, 
        headers: headers, 
        success: successCallback, 
        error: errorCallback 
    }); 
} 
  1. 在函数中添加默认参数,例如:
function ajaxRequest(url, method, data, successCallback, errorCallback, headers) { 
    headers = headers || {}; 
    $.ajax({ 
        url: url, 
        method: method, 
        data: data, 
        headers: headers, 
        success: successCallback, 
        error: errorCallback 
    }); 
} 
  1. 在函数中添加请求超时时间,例如:
function ajaxRequest(url, method, data, successCallback, errorCallback, headers, timeout) { 
    headers = headers || {}; 
    timeout = timeout || 5000; 
    $.ajax({ 
        url: url, 
        method: method, 
        data: data, 
        headers: headers, 
        timeout: timeout, 
        success: successCallback, 
        error: errorCallback 
    }); 
} 
  1. 在函数中添加请求类型,例如:
function ajaxRequest(url, method, data, successCallback, errorCallback, headers, timeout, dataType) { 
    headers = headers || {}; 
    timeout = timeout || 5000; 
    dataType = dataType || 'json'; 
    $.ajax({ 
        url: url, 
        method: method, 
        data: data, 
        headers: headers, 
        timeout: timeout, 
        dataType: dataType, 
        success: successCallback, 
        error: errorCallback 
    }); 
} 
  1. 最终的封装代码示例:
function ajaxRequest(url, method, data, successCallback, errorCallback, headers, timeout, dataType) { 
    headers = headers || {}; 
    timeout = timeout || 5000; 
    dataType = dataType || 'json'; 
    $.ajax({ 
        url: url, 
        method: method, 
        data: data, 
        headers: headers, 
        timeout: timeout, 
        dataType: dataType, 
        success: successCallback, 
        error: errorCallback 
    }); 
} 

以下是一个简单的jQuery网络请求封装,带有token验证

function requestWithToken(method, url, data, successCallback, errorCallback) { 
    var token = localStorage.getItem('token'); // 从本地存储中获取token 
    $.ajax({ 
        method: method, 
        url: url, 
        data: data, 
        headers: { 
            'Authorization': 'Bearer ' + token // 在请求头中添加token 
        }, 
        success: function(response) { 
            successCallback(response); 
        }, 
        error: function(error) { 
            errorCallback(error); 
        } 
    }); 
} 

使用方法:

requestWithToken('GET', '/api/data', null, function(response) { 
    console.log(response); 
}, function(error) { 
    console.log(error); 
}); 

在请求头中添加token可以确保请求的安全性,只有携带正确的token才能访问受保护的资源。同时,将token存储在本地存储中可以避免每次请求都需要重新输入token的麻烦。

2.4 使用封装网络请求

  1. 安装Superagent
npm install superagent --save 
  1. 创建一个封装请求的函数
import request from 'superagent'; 
const API_ROOT = '<https://api.example.com>'; 

function handleErrors(err) { 
    if (err && err.response && err.response.status === 401) { 
        // 处理未授权的错误 
    } else { 
        // 处理其他错误 
    } 
} 

function requestWrapper(method, url, data) { 
    const req = request[method.toLowerCase()](); 
    if (data) { 
        req.send(data); 
    } 
    return req.then((res) => { 
        return res.body; 
    }).catch((err) => { 
        handleErrors(err); 
        throw err; 
    }); 
} 

export default requestWrapper; 
  1. 使用封装的请求函数
import request from './requestWrapper'; 

// GET 请求 
request('get', '/users').then((data) => { 
    console.log(data); 
}).catch((err) => { 
    console.error(err); 
}); 

// POST 请求 
request('post', '/users', { name: 'John Doe', email: '<john@example.com>' }).then((data) => { 
    console.log(data); 
}).catch((err) => { 
    console.error(err); 
}); 

以下是使用Superagent进行网络请求封装并带有token验证的示例代码

import request from 'superagent'; 

const API_ROOT = '<https://example.com/api>'; 
const token = 'your_token_here'; 

const handleResponse = (res) => { 
    if (!res.ok) { 
        throw new Error(res.body.message); 
    } 
    return res.body; 
}; 

const get = (url) => { 
    return request
        .get(`${API_ROOT}${url}`)
        .set('Authorization', `Bearer ${token}`)
        .then(handleResponse); 
}; 

const post = (url, data) => { 
    return request
        .post(`${API_ROOT}${url}`)
        .set('Authorization', `Bearer ${token}`)
        .send(data) .then(handleResponse); 
}; 

const put = (url, data) => { 
    return request
        .put(`${API_ROOT}${url}`)
        .set('Authorization', `Bearer ${token}`)
        .send(data)
        .then(handleResponse); 
}; 

const del = (url) => { 
    return request
        .delete(`${API_ROOT}${url}`)
        .set('Authorization', `Bearer ${token}`)
        .then(handleResponse); 
}; 

export default { get, post, put, del, }; 

在上面的代码中,我们首先定义了API的根路径和token。然后,我们定义了四个函数:get、post、put和del,分别对应HTTP的GET、POST、PUT和DELETE方法。这些函数都接受一个URL和一个可选的数据对象作为参数,并使用Superagent发送网络请求。在每个请求中,我们都设置了Authorization头,将token作为Bearer令牌发送。最后,我们导出这些函数,以便在其他地方使用。