当前位置: 首页 > news >正文

Uniapp 网络请求封装专题

目录

一、前言

二、uniapp官方文档

三、举例演示

3.1 使用说明

3.2 Content-Type

3.2.1 ​​基本概念

​​3.2.2 核心作用

3.2.3 常见 Content-Type 类型及使用场景

1)文本类

a)text/plain​​​​

b)text/html​​   

2)应用类

a)application/json​​   

b)application/x-www-form-urlencoded  

3)多媒体类

image/jpeg​​、​​video/mp4

4)特殊类型​​

  ​​application/octet-stream​​

3.2.4 关键注意事项

3.3 success参数

3.3.1 基础回调函数写法

3.3.2 分离函数(外部定义)

三、Promise

3.1 是什么

3.2 核心思想

3.3 ​Promise 的三种状态​

3.4 基本用法与语法

3.4.1 创建 Promise​

3.4.2 ​​处理结果​​

3.4.3 链式调用​​

 四、封装

五、调用演示


一、前言

在前文中,我们介绍了uniapp中如何发送请求,并完成了基础的二次封装。虽然直接复用示例代码可以快速上手,但面对复杂项目时,往往需要根据实际需求重新设计网络请求模块。

对于前端经验较少的开发者来说,深度封装可能具有一定挑战性。本文旨在梳理不同项目的封装思路,帮助大家掌握核心逻辑,从而能够灵活应对各种业务场景的需求变化。

二、uniapp官方文档

首先给出uniapp发送网络请求的官网文档,然后再带领大家一起解读。uni.request(OBJECT) | uni-app官网

uni.request(OBJECT)

OBJECT 参数说明

参数名类型必填默认值说明平台差异说明
urlString开发者服务器接口地址
dataObject/String/ArrayBuffer请求的参数App 3.3.7 以下不支持 ArrayBuffer 类型
headerObject设置请求的 header,header 中不能设置 RefererApp、H5端会自动带上cookie,且H5端不可手动修改
methodStringGET有效值详见下方说明
timeoutNumber60000超时时间,单位 msH5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序
dataTypeStringjson如果设为 json,会对返回的数据进行一次 JSON.parse,非 json 不会进行 JSON.parse
responseTypeStringtext设置响应的数据类型。合法值:text、arraybuffer支付宝小程序不支持
sslVerifyBooleantrue验证 ssl 证书仅App安卓端支持(HBuilderX 2.3.3+),不支持离线打包
withCredentialsBooleanfalse跨域请求时是否携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+)
firstIpv4BooleanfalseDNS解析时优先使用ipv4仅 App-Android 支持 (HBuilderX 2.8.0+)
enableHttp2Booleanfalse开启 http2微信小程序
enableQuicBooleanfalse开启 quic微信小程序
enableCacheBooleanfalse开启 cache微信小程序、抖音小程序 2.31.0+
enableHttpDNSBooleanfalse是否开启 HttpDNS 服务。如开启,需要同时填入 httpDNSServiceId 。 HttpDNS 用法详见 移动解析HttpDNS微信小程序
httpDNSServiceIdStringHttpDNS 服务商 Id。 HttpDNS 用法详见 移动解析HttpDNS微信小程序
enableChunkedBooleanfalse开启 transfer-encoding chunked微信小程序
forceCellularNetworkBooleanfalsewifi下使用移动网络发送请求微信小程序
enableCookieBooleanfalse开启后可在headers中编辑cookie支付宝小程序 10.2.33+
cloudCacheObject/Booleanfalse是否开启云加速(详见云加速服务)百度小程序 3.310.11+
deferBooleanfalse控制当前请求是否延时至首屏内容渲染后发送百度小程序 3.310.11+
successFunction收到开发者服务器成功返回的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

method 有效值

注意:method有效值必须大写,每个平台支持的method有效值不同,详细见下表。

methodAppH5微信小程序支付宝小程序百度小程序抖音小程序、飞书小程序快手小程序京东小程序
GET
POST
PUTxxx
DELETExxxx
CONNECTxxxxxx
HEADxxxx
OPTIONSxxxx
TRACExxxxxx

可见,请求方式主推使用GET、POST。

success 返回参数说明

参数类型说明
dataObject/String/ArrayBuffer开发者服务器返回的数据
statusCodeNumber开发者服务器返回的 HTTP 状态码
headerObject开发者服务器返回的 HTTP Response Header
cookiesArray.<string>开发者服务器返回的 cookies,格式为字符串数组

三、举例演示

3.1 使用说明

这里我们找一个免费的api接口进行测试。

mounted() {this.test()},
methods: {test() {uni.request({url: 'https://route.showapi.com/9-2?appKey=E53C00b070ce4Ee0b2B77365af35993c',method: 'POST',header: { 'content-type': 'application/x-www-form-urlencoded' }, data:{area: '重庆'},success: (res) => { console.log("请求成功",res);}})}
}

打开页面调用控制台看一下

调用成功!

3.2 Content-Type

3.2.1 ​​基本概念

Content-Type 是 HTTP 协议中用于标识请求响应体数据类型头部字段,属于 MIME(多用途互联网邮件扩展)类型的一种。其格式为:

Content-Type: <type>/<subtype>; <parameters>

​type​​:主类型(如 textapplicationimage

​subtype​​:子类型(如 htmljsonjpeg

parameters​​:可选参数(如 charset=UTF-8boundary 用于分段数据)

​​3.2.2 核心作用

客户端请求​​:告知服务器如何解析请求体(如 JSON 或表单数据)

服务器响应​​:指导客户端(如浏览器)如何处理返回的数据(如渲染 HTML 或下载文件)

3.2.3 常见 Content-Type 类型及使用场景

1)文本类
a)text/plain​​​​

 纯文本数据,适用于日志或简单消息。

Content-Type: text/plain; charset=UTF-8
b)text/html​​   

 HTML 文档,用于网页渲染。

// 后端设置示例
res.setHeader('Content-Type', 'text/html');
2)应用类
a)application/json​   

JSON格式数据,适合传输结构化数据(如 API 交互)。

前端请求示例​​:

fetch('/api', {headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ key: 'value' })
});

后端接收​​(Spring Boot) 

@PostMapping("/api")
public ResponseEntity<?> handleJson(@RequestBody User user) { ... }
b)application/x-www-form-urlencoded  

 表单默认提交格式,数据编为 key=value&key2=value2

前端请求示例

uni.request({url: 'https://route.showapi.com/9-2?appKey=E53C00b070ce4Ee0b2B77365af35993c',method: 'POST',header: { 'content-type': 'application/x-www-form-urlencoded' }, data:{area: '重庆'},success: (res) => { console.log("请求成功",res);}
})

后端SpringBoot接收方式

  • 使用 @RequestParam 注解
    • 适用于直接接收表单字段,字段名需与前端参数名一致
    • @PostMapping("/login")
      public String login(@RequestParam String username, @RequestParam String password) {return "用户名:" + username + ",密码:" + password;
      }
    • ​注意​​:若参数名不一致,需指定 @RequestParam("前端字段名")
  • 通过 Map 或 LinkedHashMap 接收
    • 适用于动态或大量字段的场景:
    • @PostMapping("/submit")
      public ResponseEntity<?> submit(@RequestParam Map<String, String> params) {System.out.println(params); // 输出所有键值对return ResponseEntity.ok(params);
      }
    •  优点:无需预定义字段,灵活性强
  • 避免使用 @RequestBody
    • x-www-form-urlencoded 数据默认不支持 @RequestBody 绑定到自定义对象,否则会报错 Content-Type not supported。若需绑定到对象,需改用 @ModelAttribute 或直接通过字段接收。

3)多媒体类
image/jpeg​​、​​video/mp4

分别用于 JPEG 图片和 MP4 视频,常见于资源加载或文件下载。

响应头示例

Content-Type: image/png
Content-Disposition: attachment; filename="example.png"
4)特殊类型​​
  ​application/octet-stream

二进制流,适用于任意文件下载

// 后端设置
res.setHeader('Content-Type', 'application/octet-stream');

 

3.2.4 关键注意事项

字符编码​

文本类数据需指定 charset(如 UTF-8),避免乱码。

​与后端的匹配​

  • 使用 @RequestBody 接收 JSON 时,必须设置 Content-Type: application/json
  • 表单数据需对应 @RequestParam ,设置 application/x-www-form-urlencoded 或 FormData

​错误处理​

  • 错误的 Content-Type 可能导致 HTTP 415(不支持的媒体类型)。
  • 文件上传时若手动设置 multipart/form-data 的 boundary,需确保格式正确。

Content-Type 是 HTTP 通信的“语言协议”,正确设置可确保数据解析无误。开发中需根据场景选择类型:

  • ​API 交互​​ → application/json
  • ​表单提交​​ → application/x-www-form-urlencoded
  • ​文件上传​​ → multipart/form-data
  • ​资源加载​​ → 对应媒体类型(如 image/png

 

3.3 success参数

在uniapp中,uni.request 方法的 success 参数用于处理请求成功的回调,其写法灵活多样,可以根据开发场景和编码风格选择。以下是常见的几种写法及详细说明:

3.3.1 基础回调函数写法

匿名函数(直接定义)

直接在 success 属性中定义匿名函数,适用于简单逻辑:

uni.request({url: 'https://api.example.com/data',success: function(res) {console.log('请求成功:', res.data); // 输出响应数据// 其他逻辑处理},fail: (err) => { console.error('请求失败:', err); }
});

特点​​:代码直观,适合快速开发或单次请求场景

注意​​:res 参数包含 data(响应体)、statusCode(HTTP状态码)、header(响应头)等属性

 箭头函数(ES6语法)

使用箭头函数简化作用域绑定,避免 this 指向问题

uni.request({url: 'https://api.example.com/data',success: (res) => {this.dataList = res.data; // 直接访问组件实例的data}
});

 适用场景​​:Vue 组件中需要访问 this 时推荐使用

3.3.2 分离函数(外部定义)

将回调逻辑抽离为独立函数,提升代码复用性

function handleSuccess(res) {if (res.statusCode === 200) {console.log('数据:', res.data);} else {console.error('服务器异常:', res.statusCode);}
}uni.request({url: 'https://api.example.com/data',success: handleSuccess // 传入函数引用
});
  • ​优点​​:逻辑清晰,便于复用和单元测试。
  • ​扩展​​:可结合错误状态码统一处理(如 401 跳转登录页)

三、Promise

3.1 是什么

Promise 是 JavaScript 中用于处理异步操作的核心对象,它代表一个异步操作的最终完成(或失败)及其结果值。以下是关于 Promise 的详细解析,综合了多个搜索结果中的核心信息。

Promise 是一个容器,用于封装异步操作(如网络请求、定时器、文件读取等),并通过状态管理来追踪其完成情况。它允许开发者以更清晰的方式处理异步逻辑,避免传统的“回调地狱”。

3.2 核心思想

延迟绑定​​:Promise 将异步操作的结果与处理逻辑分离,通过链式调用(.then().catch())注册回调函数,而非嵌套回调。

状态不可逆​​:Promise 的状态一旦改变(从 pending 到 fulfilled 或 rejected),便不可再变。

3.3 ​Promise 的三种状态​

​​Pending(进行中)​​

初始状态,表示异步操作尚未完成。

​​Fulfilled(已成功)​​

异步操作成功完成,通过 resolve(value) 触发,此时 .then() 的回调函数会被执行。

Rejected(已失败)​​

异步操作失败,通过 reject(error) 触发,此时 .catch() 或 .then() 的第二个参数会捕获错误。

3.4 基本用法与语法

3.4.1 创建 Promise​

const promise = new Promise((resolve, reject) => {// 异步操作(如 setTimeout、AJAX)if (/* 成功 */) resolve(value); // 状态变为 fulfilledelse reject(new Error('失败原因')); // 状态变为 rejected
});

例如:

return new Promise((resolve, reject) => {uni.request({...options,success: (res) => {if(res.data.code === 1) {resolve(res.data);}else{// 统一错误处理(如token过期)if(res.data.code === -1 || res.data.code === -3) {uni.navigateTo({url:'/pages/login/login'})}reject(res.data);}},fail: (err) => {uni.showToast({ title: '网络错误', icon: 'none' });reject(err);}})
})

3.4.2 ​​处理结果​​

.then()​:处理成功状态,接收 resolve 传递的值

promise.then((result) => console.log(result));

.catch()​:处理失败状态,捕获 reject 或代码抛出的错误 

promise.catch((error) => console.error(error));

.finally()​:无论成功或失败都会执行,常用于清理逻辑 

3.4.3 链式调用​​

Promise 的 .then() 返回一个新的 Promise,支持连续调用:

fetchData().then(processData).then(saveData).catch(handleError);

 

 四、封装

我们使用Promise来封装请求。具体的,先给出结果,然后再一点点讲。

定义一个request.js文件

名字不重要,叫什么都可以,目的是通过Promise封装我们的uni.request函数。

import {BASE_URL} from '@/common/config.js'export const myRequest = (options) => {// 自动拼接请求地址options.url = BASE_URL + options.url;// 默认请求头options.header = {'Authorization': uni.getStorageSync('token') || '','Content-Type': 'application/json',...options.header // 允许调用者覆盖};// return new Promise((resolve, reject) => {uni.request({...options,success: (res) => {if(res.data.code === 1) {resolve(res.data);}else{// 统一错误处理(如token过期)if(res.data.code === -1 || res.data.code === -3) {uni.navigateTo({url:'/pages/login/login'})}reject(res.data);}},fail: (err) => {uni.showToast({ title: '网络错误', icon: 'none' });reject(err);}})})}

解读: 

在这个js文件中,我们通过ES6 模块化规范的导入语法,导入了根目录下的common包中的config.js文件中的BASE_URL。这样做的目的是通过某一个配置文件来集中定义一些通用的配置,方便修改和维护。

config.js

// common/config.js
export const BASE_URL = 'http://106.75.224.22:8090'; // 基础域名

api统一封装

import {myRequest} from '@/utils/request.js'export const loginApi = (username, password) => {return myRequest({url: '/api/login',method: 'POST',data: {username, password}})
};export const getStatisticApi = (date) => {const params = date ? { date } : {};return myRequest({url: '/api/keepAccount/getStatistic',method: 'GET',data: params,})
};export const addAccountApi = (event, money, type, happenDate) => {return myRequest({url: '/api/keepAccount/addAccount',method: 'POST',data: {event,money,type,happenDate}})
};export const getListApi = (date) => {return myRequest({url: '/api/keepAccount/getList',method: 'GET',data: {date}})
};

五、调用演示

handleLogin() {if (!this.canLogin) return// 这里替换为实际的登录逻辑uni.showLoading({title: '登录中...'})// 调用登录接口loginApi(this.username, this.password).then(res => {uni.showToast({title: '登录成功',icon: 'success'});// 保存到本地token// 注意这里为什么不是res.data.data。是因为我们request.js封装的时候,返回的res对象其实是res.data,而非最初的res对象。uni.setStorageSync("token", res.data);setTimeout(() => {uni.reLaunch({url: '/pages/index/index'});}, 1500);}).catch(error => {console.error('登录失败:', error);uni.showToast({title: error.msg,icon: 'none'});}).finally(() => {uni.hideLoading();});console.log("你好");
}

在这个handleLogin()方法中,​​控制台会先打印“你好”,然后才会处理请求的返回结果​。

因为它是同步代码,而 Promise 回调是异步的微任务。

网络请求的响应时间不确定,但其回调一定在同步代码之后执行。

如果需要强制等待请求完成再执行后续逻辑,需使用 async/await 改写:

async handleLogin() {console.log("你好"); // 仍会先执行await loginApi(this.username, this.password).then(/* ... */);console.log("请求完成后才执行"); // 微任务之后
}

怎么样,现在是不是清楚整个封装流程了?🫠

如果有什么疑问或者表述错误地方,也欢迎小伙伴们一起沟通、交流和指正~~~

相关文章:

  • LeetCode 662. 二叉树的最大宽度
  • IP 地理库的使用指南:从基础应用到深度实践​
  • 国产MCU A\B SWAP原理及实操
  • 生产事故复盘--小问题引发的大事故
  • Kafka存储设计深度剖析:日志、索引与文件管理的底层奥秘
  • JavaScript 中 call、apply 和 bind 的区别
  • Unity_VR_如何用键鼠模拟VR输入
  • SSH远程连接
  • Linux 进程概念
  • 【蓝牙】手机连接Linux系统蓝牙配对,Linux Qt5分享PDF到手机
  • 如何将缓存存到客户端浏览器上呢
  • [11-5]硬件SPI读写W25Q64 江协科技学习笔记(20个知识点)
  • VR看房:重塑房地产行业生态的技术革命
  • Vim-vimrc 快捷键映射
  • Minio使用https自签证书
  • Excel学习01
  • 面试题:设计一个分布式“附近的人”功能(如微信附近的人、交友应用位置匹配)
  • 数字华容道智力小游戏微信流量主小程序开源
  • ros中相机话题在web页面上的显示,尝试js解析sensor_msgs/Image数据
  • DHCP服务
  • 中央农村工作会议2024/绍兴seo排名收费
  • 石家庄市工程建设造价管理站网站/广州seo关键词优化外包
  • 代做财务报表分析网站/微博指数
  • 怎么用服务器lp做网站/微商软文推广平台
  • 短剧cps分销平台官网/北京seo网站开发
  • 关于做美食的网站/查关键词排名网