JavaScript 如何做请求封装

很多做前端开发的朋友,刚开始写代码时,总是会在各个页面里重复写调用接口的代码:写一遍发请求的逻辑,写一遍处理返回数据的逻辑,再写一遍报错的处理逻辑。久而久之,项目里就会出现大量重复的代码,改一个请求配置要找遍所有文件,出了问题也难排查。这时候就需要用请求封装来解决这些麻烦,它就像一个“统一的快递收发站”,把所有发请求的流程都整理好,需要发请求时直接来这里取配置就行。

先搞懂:为什么要做请求封装?

举个生活化的例子:你平时寄快递,每次都要自己找纸箱、缠胶带、填收件人地址,不仅费时间还容易出错。如果有个快递站,你只需要告诉工作人员“我要寄到XX地址”,剩下的打包、贴单、找快递员全由他们搞定,是不是省心很多?

JavaScript 如何做请求封装

请求封装也是这个道理。比如你要调用一个获取用户信息的接口,封装前你可能会写:

`javascript

fetch('https://你的接口地址/user/info', {

method: 'GET',

headers: { 'token': '当前用户的登录令牌' }

})

.then(res => res.json())

.catch(err => console.log('请求出错了', err));

`

要是换一个接口,还要重复写headers、catch这些内容,万一令牌过期了,每个地方都要改,太麻烦。封装后,你只需要写request('/user/info', 'GET')就行,剩下的统一处理。

第一步:搭一个简单的请求封装骨架

我们可以用最常用的fetch或者axios来做封装,这里用fetch举例子(axios的逻辑类似,只是语法稍有不同)。先建一个request函数,把固定的配置都写进去。

比如,所有请求都需要带登录令牌,都要处理返回的格式,出错了要统一提示,这些都可以放在封装里:

`javascript

// 基础配置:接口前缀,这样写不同环境(开发/生产)不用改接口地址

const BASE_URL = 'https://你的项目接口地址';

async function request(url, method = 'GET', data = null) {

// 从本地存储拿登录令牌,所有请求自动带上,不用每次写

const token = localStorage.getItem('userToken');

// 统一的请求头,固定的内容直接放这里

const headers = {

'Content-Type': 'application/json',

'token': token || ''

};

// 拼接完整的接口地址

const fullUrl = BASE_URL + url;

// 处理请求参数,GET请求放地址里,POST/PUT放请求体里

const options = { method, headers };

if (data && ['POST', 'PUT'].includes(method)) {

options.body = JSON.stringify(data);

}

try {

// 发请求,返回结果

const response = await fetch(fullUrl, options);

const result = await response.json();

// 统一处理业务逻辑:比如后端返回的code代表状态,code为401说明令牌过期,统一跳登录页

if (result.code === 401) {

localStorage.removeItem('userToken');

window.location.href = '/login';

return Promise.reject('登录已过期');

}

return result;

} catch (err) {

// 统一处理报错:比如网络不好时弹提示

console.log('请求失败,请检查网络', err);

return Promise.reject(err);

}

}

`

第二步:用封装好的函数发请求,有多省心?

封装完成后,不管是获取用户信息、提交表单还是删除商品,都只需要简单调用,不用再重复写一堆逻辑。比如:

`javascript

// 1. 获取用户信息(GET请求)

request('/user/info').then(res => {

console.log('用户信息', res.data);

});

// 2. 提交用户注册信息(POST请求)

request('/user/register', 'POST', {

username: '小明',

password: '123456'

}).then(res => {

alert('注册成功');

});

// 3. 删除商品(DELETE请求)

request('/product/123', 'DELETE').then(res => {

alert('删除成功');

});

`

要是以后需要改逻辑,比如把fetch换成axios,或者修改令牌的存储位置,只需要改封装里的request函数,所有调用它的地方都会自动更新,完全不用动业务代码。

最后:封装时要注意的小细节

很多新手封装时会忽略几个小问题,导致踩坑:

一是环境区分:开发时用本地测试接口,上线后用正式接口,封装里可以加个判断:

`javascript

const BASE_URL = process.env.NODE_ENV === 'development'

? 'http://localhost:3000'

: 'https://你的正式接口地址';

`

二是参数兼容:GET请求的参数要拼在地址后面,不能直接放请求体里,封装时要单独处理GET的参数拼接;

三是错误统一:不要只在封装里打日志,还要给业务代码留处理错误的入口,比如request返回Promise,业务代码可以自己处理特定的错误场景。

这样一套封装下来,不仅代码少了一半,后续维护、改需求也会轻松很多,是前端开发里非常实用的小技巧。

上一篇 C / C++核心语法与编程规范 零基础入门必掌握的实用知识科普