Uniapp 网络请求封装专题

发布于:2025-06-20 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

一、前言

二、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 参数说明

参数名 类型 必填 默认值 说明 平台差异说明
url String 开发者服务器接口地址
data Object/String/ArrayBuffer 请求的参数 App 3.3.7 以下不支持 ArrayBuffer 类型
header Object 设置请求的 header,header 中不能设置 Referer App、H5端会自动带上cookie,且H5端不可手动修改
method String GET 有效值详见下方说明
timeout Number 60000 超时时间,单位 ms H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序
dataType String json 如果设为 json,会对返回的数据进行一次 JSON.parse,非 json 不会进行 JSON.parse
responseType String text 设置响应的数据类型。合法值:text、arraybuffer 支付宝小程序不支持
sslVerify Boolean true 验证 ssl 证书 仅App安卓端支持(HBuilderX 2.3.3+),不支持离线打包
withCredentials Boolean false 跨域请求时是否携带凭证(cookies) 仅H5支持(HBuilderX 2.6.15+)
firstIpv4 Boolean false DNS解析时优先使用ipv4 仅 App-Android 支持 (HBuilderX 2.8.0+)
enableHttp2 Boolean false 开启 http2 微信小程序
enableQuic Boolean false 开启 quic 微信小程序
enableCache Boolean false 开启 cache 微信小程序、抖音小程序 2.31.0+
enableHttpDNS Boolean false 是否开启 HttpDNS 服务。如开启,需要同时填入 httpDNSServiceId 。 HttpDNS 用法详见 移动解析HttpDNS 微信小程序
httpDNSServiceId String HttpDNS 服务商 Id。 HttpDNS 用法详见 移动解析HttpDNS 微信小程序
enableChunked Boolean false 开启 transfer-encoding chunked 微信小程序
forceCellularNetwork Boolean false wifi下使用移动网络发送请求 微信小程序
enableCookie Boolean false 开启后可在headers中编辑cookie 支付宝小程序 10.2.33+
cloudCache Object/Boolean false 是否开启云加速(详见云加速服务 百度小程序 3.310.11+
defer Boolean false 控制当前请求是否延时至首屏内容渲染后发送 百度小程序 3.310.11+
success Function 收到开发者服务器成功返回的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

method 有效值

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

method App H5 微信小程序 支付宝小程序 百度小程序 抖音小程序、飞书小程序 快手小程序 京东小程序
GET
POST
PUT x x x
DELETE x x x x
CONNECT x x x x x x
HEAD x x x x
OPTIONS x x x x
TRACE x x x x x x

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

success 返回参数说明

参数 类型 说明
data Object/String/ArrayBuffer 开发者服务器返回的数据
statusCode Number 开发者服务器返回的 HTTP 状态码
header Object 开发者服务器返回的 HTTP Response Header
cookies Array.<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); // 状态变为 fulfilled
  else 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("请求完成后才执行"); // 微任务之后
}

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

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


网站公告

今日签到

点亮在社区的每一天
去签到