uniapp --发送请求请求数据
'# uniapp --发送请求请求数据
一、背景与问题
在uni-app开发中,网络请求是连接前后端的核心桥梁。开发者需要通过uni.request等API与服务器进行数据交互,但实际开发中常遇到以下挑战:
- 跨域问题:微信小程序等平台对跨域请求有严格限制
- 请求参数复杂性:需要处理Token、签名、时间戳等安全参数
- 网络状态异常:需要处理断网、超时、弱网等场景
- 数据格式转换:JSON/FormData等不同格式的处理
- 平台差异:微信小程序与H5的差异处理
理解uni-app网络请求的底层原理和最佳实践,是构建稳定可靠应用的关键。
二、基本原理
uni-app的网络请求机制基于原生平台的网络API,通过JavaScript层封装实现跨平台支持。其核心原理如下:
- 请求封装:通过uni.request将请求参数转换为原生平台可识别的格式
- 跨平台适配:根据运行平台选择不同的网络实现(微信小程序使用wx.request,H5使用fetch)
- 异步处理:基于Promise的异步请求机制
- 数据转换:自动处理JSON格式的响应数据
关键流程:
用户触发请求 → uni.request → 平台原生网络API → 服务器响应 → 数据解析 → 回调处理三、环境准备
- 开发环境:HBuilderX 3.x + Node.js 16+
- 服务器环境:支持CORS的Node.js服务(使用express)
- 配置文件:
manifest.json中配置网络请求域名(微信小程序必填)
{
"network": {
"request": {
"enable": true,
"url": "https://yourdomain.com"
}
}
}四、核心实现
1. 基础请求实现
// pages/index/index.vue
<template>
<view>
<button @click="fetchData">获取数据</button>
<view>{{ data }}</view>
</view>
</template>
<script>
export default {
data() {
return {
data: null
};
},
methods: {
async fetchData() {
try {
const res = await uni.request({
url: 'https://yourdomain.com/api/data',
method: 'GET'
});
this.data = res.data;
} catch (err) {
console.error('请求失败:', err);
}
}
}
};
</script>关键代码解释:
uni.request返回Promise对象method参数指定HTTP方法(GET/POST等)url需要配置到manifest.json中(微信小程序必填)async/await处理异步请求
2. 带Token的请求实现
// utils/request.js
export function request(config) {
return new Promise((resolve, reject) => {
uni.request({
...config,
header: {
...config.header,
'Authorization': `Bearer ${uni.getStorageSync('token')}`
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res);
}
},
fail: (err) => {
reject(err);
}
});
});
}// pages/index/index.vue
<template>
<view>
<button @click="fetchProtectedData">获取受保护数据</button>
<view>{{ protectedData }}</view>
</view>
</template>
<script>
import { request } from '@/utils/request';
export default {
data() {
return {
protectedData: null
};
},
methods: {
async fetchProtectedData() {
try {
const res = await request({
url: 'https://yourdomain.com/api/protected',
method: 'GET'
});
this.protectedData = res;
} catch (err) {
console.error('受保护数据请求失败:', err);
}
}
}
};
</script>关键代码解释:
- 自定义封装的request函数,统一处理Token
- 使用uni.getStorageSync获取存储的token
- 通过header添加Authorization头
- 处理不同状态码的响应
3. 错误处理与重试机制
// utils/request.js
export function request(config) {
return new Promise((resolve, reject) => {
uni.request({
...config,
header: {
...config.header,
'X-Request-ID': Date.now().toString(36)
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res);
}
},
fail: (err) => {
// 自动重试机制(最多3次)
const retryCount = parseInt(err?.config?.retryCount || 0);
if (retryCount < 3) {
uni.request({
...config,
retryCount: retryCount + 1
});
} else {
reject(err);
}
}
});
});
}关键代码解释:
- 添加请求ID用于日志追踪
- 实现自动重试机制(最多3次)
- 在fail回调中处理网络异常
- 通过配置参数传递重试次数
五、完整案例
登录功能实现(完整案例)
1. 服务端接口(Node.js)
// server.js
const express = require('express');
const app = express();
const port = 3000;
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
// 模拟数据库验证
if (username === 'admin' && password === '123456') {
res.status(200).json({
token: 'super-secret-token'
});
} else {
res.status(401).json({ error: '认证失败' });
}
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});2. 客户端代码(uni-app)
<!-- pages/login/login.vue -->
<template>
<view>
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button @click="login">登录</button>
<view v-if="token">{{ token }}</view>
</view>
</template>
<script>
export default {
data() {
return {
username: '',
password: '',
token: null
};
},
methods: {
async login() {
try {
const res = await this.$request({
url: 'https://yourdomain.com/api/login',
method: 'POST',
data: {
username: this.username,
password: this.password
}
});
uni.setStorageSync('token', res.token);
this.token = res.token;
} catch (err) {
console.error('登录失败:', err);
}
}
}
};
</script>关键代码解释:
- 使用自定义的$request封装
- 处理登录响应并存储token
- 使用uni.setStorageSync保存token
- 在后续请求中自动携带token
六、源码解析
uni-app的request方法源码核心逻辑(以微信小程序为例):
// node_modules/uni-app/manifest/manifest.js
function request(options) {
return new Promise((resolve, reject) => {
wx.request({
url: options.url,
method: options.method || 'GET',
header: {
...options.header,
'X-Platform': 'wechat'
},
data: options.data,
success: (res) => {
resolve(res.data);
},
fail: (err) => {
reject(err);
}
});
});
}关键点解析:
- 自动添加平台标识头
- 支持不同的HTTP方法
- 自动处理响应数据
- 提供统一的Promise接口
七、进阶使用
1. 请求拦截器
// utils/request.js
export function request(config) {
return new Promise((resolve, reject) => {
uni.request({
...config,
header: {
...config.header,
'X-Request-ID': Date.now().toString(36),
'X-Platform': 'uni-app'
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res);
}
},
fail: (err) => {
reject(err);
}
});
});
}2. 响应拦截器
export function request(config) {
return new Promise((resolve, reject) => {
uni.request({
...config,
success: (res) => {
if (res.statusCode === 200) {
const data = res.data;
if (data.code === 200) {
resolve(data.data);
} else {
reject(data.message || '服务器错误');
}
} else {
reject(res);
}
},
fail: (err) => {
reject(err);
}
});
});
}3. 基于Promise的链式调用
async function fetchData() {
try {
const data = await request({
url: 'https://yourdomain.com/api/data'
});
console.log('获取到数据:', data);
} catch (err) {
console.error('请求失败:', err);
}
}八、性能与工程实践
1. 性能优化方案
| 优化策略 | 说明 | 实现方式 |
|---|---|---|
| 响应压缩 | 减少传输数据量 | 使用Gzip压缩 |
| 缓存策略 | 减少重复请求 | 使用uni.setStorageSync |
| 并行请求 | 提高请求效率 | 使用Promise.all |
| 资源预加载 | 提前加载常用接口 | 在App启动时预加载 |
2. 异常处理机制
export function request(config) {
return new Promise((resolve, reject) => {
uni.request({
...config,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
// 记录错误日志
uni.$log.error(`请求失败: ${res.statusCode}`);
reject(res);
}
},
fail: (err) => {
// 记录网络错误
uni.$log.error('网络错误:', err);
reject(err);
}
});
});
}3. 安全加固方案
| 风险类型 | 解决方案 | 实现方式 |
|---|---|---|
| Token泄露 | 使用刷新Token机制 | 存储在本地缓存并设置过期时间 |
| 明文传输 | 使用HTTPS协议 | 配置服务器支持HTTPS |
| 跨域攻击 | 配置CORS头 | 设置Access-Control-Allow-Origin |
| SQL注入 | 参数化查询 | 使用预处理语句 |
九、常见问题与踩坑
1. 跨域问题解决方案
错误场景:微信小程序访问非备案域名
解决方法:
配置服务器CORS头:
res.header('Access-Control-Allow-Origin', '*');- 使用uni-app云开发的云函数作为代理
- 在manifest.json中配置合法域名
2. 网络状态异常处理
错误场景:断网时请求失败
解决方法:
添加网络状态检测:
uni.getNetworkType({ success: (res) => { if (res.isConnected === false) { uni.showToast({ title: '无网络', icon: 'none' }); } } });- 实现离线缓存机制
- 使用uni.getStorageSync存储离线数据
3. 请求参数处理问题
错误场景:FormData格式参数处理失败
解决方法:
- 使用
uni.createSelectorQuery获取表单数据 - 使用
uni.getStorageInfo获取存储数据 - 使用
uni.setStorage设置复杂数据类型 - 使用
uni.getSystemInfoSync获取设备信息
十、最佳实践
- 统一请求封装:创建
request.js统一处理请求 - 错误日志记录:使用
uni.$log记录请求日志 - Token管理:使用
uni.getStorageSync安全存储 - 请求拦截:添加请求ID进行日志追踪
- 响应拦截:统一处理成功/失败状态码
- 性能监控:记录请求耗时进行优化
- 安全加固:强制使用HTTPS协议
- 异常处理:添加重试机制和网络状态检测
- 版本管理:使用
uni.getSystemInfoSync获取客户端版本 - 接口文档:维护接口文档进行版本管理
十一、总结
uni-app的网络请求机制是连接前后端的核心桥梁,理解其工作原理和最佳实践对开发高质量应用至关重要。通过本文的深入探讨,我们掌握了:
- uni-app网络请求的基本原理和实现方式
- 多种请求场景的代码实现和关键点
- 实际开发中常见的问题和解决方案
- 性能优化和安全加固的策略
- 完整的请求流程和异常处理机制
在实际开发中,建议根据具体需求选择合适的请求策略。对于需要频繁请求的场景,推荐使用请求拦截器和响应拦截器进行统一管理;对于敏感数据传输,务必使用HTTPS协议并妥善管理Token;在性能敏感场景中,需要结合缓存策略和压缩技术进行优化。通过合理的设计和实现,可以构建出稳定、高效、安全的uni-app应用。
评论已关闭