uniapp基础(五)调试与错误
目录
一、编译错误的常见类型及解决方法
1. 依赖冲突或缺失
2. 语法错误
3. 路径引用错误
4. 平台特有代码未适配
5. 组件注册失败
6. 分包配置错误
7. 原生插件集成问题
8.manifest.json 格式错误
9. pages.json 路由配置错误
10. 内存不足
错误日志:
常见触发场景
排查方法
解决方案优化
进阶调试技巧
11.网络请求错误
(1).跨域问题
(2).404接口路径错误
(3).400参数格式错误
(4).500服务器端错误
(6).网络连接问题
UniApp中的网络请求示例
错误处理建议
12. TypeScript 类型错误
(1).类型不匹配错误
(2).缺少必要属性
(3).函数参数类型不匹配
(4).未识别的属性
错误排查通用步骤
二、处理跨域问题的方法?
1.配置本地开发服务器代理
2.使用后端设置 CORS 头
3.使用 JSONP 请求
4.使用云函数中转请求
5.生产环境使用 Nginx 反向代理
注意事项
三、如何捕获并处理全局错误?
1.使用 onError 生命周期钩子
2.监听 UnhandledRejection(Promise 错误)
3.封装请求拦截器
错误处理的最佳实践
注意事项
四、小程序白屏
检查网络连接
优化代码包体积
预加载关键资源
启用骨架屏
检查页面路由堆栈
监控异常并上报
兼容性处理
内存管理优化
一、编译错误的常见类型及解决方法
1. 依赖冲突或缺失
错误日志:
npm ERR! conflict 或 Version mismatch。
Module not found: Error: Can't resolve 'xxx' in '.../node_modules/@dcloudio/uni-ui/lib/xxx'
解决方法: 检查 package.json
文件中的依赖版本,确保所有依赖版本兼容。可以使用 npm install
或 yarn install
重新安装依赖。若涉及第三方库,需确认是否兼容当前 UniApp 版本。
2. 语法错误
错误日志:
ERROR in ./src/pages/index/index.vue
SyntaxError: Unexpected token ';' in JSON at position 100
解决方法: 检查代码中是否有拼写错误、缺少括号或分号,使用 ESLint 或代码编辑器检查语法,确保 JSON 文件无逗号结尾、JS 代码符合 ES 规范,CSS 选择器书写正确。
3. 路径引用错误
错误日志:
Error: ENOENT: no such file or directory, open '.../static/xxx.png'
解决方法:检查文件路径是否正确,检查静态资源路径是否以 /static/
开头,或使用 @/static/
绝对路径。使用相对路径或绝对路径时需确保路径有效
4. 平台特有代码未适配
错误日志:
TypeError: uni.requireNativePlugin is not a function (H5环境)
解决方法: 使用条件编译区分平台:
// #ifdef APP-PLUS
const plugin = uni.requireNativePlugin('xxx')
// #endif
5. 组件注册失败
错误日志:
Unknown custom element: <uni-badge> - did you register the component correctly?
解决方法: 确认组件已在 pages.json
或全局组件中正确注册。全局组件需在 main.js
注册,检查组件名称拼写是否正确。
import uniBadge from '@dcloudio/uni-ui/lib/uni-badge/uni-badge.vue'
Vue.component('uni-badge', uniBadge)
6. 分包配置错误
错误日志:
Subpackage loading failed: xxx/subpackage is not found
解决方法: 检查 pages.json
分包路径配置:
{"subPackages": [{"root": "subpackage","pages": [...]}]
}
7. 原生插件集成问题
错误日志:
Failed to execute 'postMessage' on 'WebView'
解决方法: 确认原生插件已按文档正确配置,Android 需检查 AndroidManifest.xml
,iOS 需检查 Info.plist
。
8.manifest.json
格式错误
// 错误的 manifest.json 配置
{"name": "myApp","appid": "12345","description": "示例应用",// 缺少闭合括号
错误日志:
ERROR: Failed to parse manifest.json
Unexpected end of JSON input
at JSON.parse (<anonymous>)
解决方法:检查 JSON 文件格式,确保所有括号、引号闭合,使用 JSON 校验工具(如 JSONLint)验证文件内容。
9. pages.json
路由配置错误
// 错误的 pages.json 配置
{"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页"}},// 缺少 path 字段{"style": {"navigationBarTitleText": "详情页"}}]
}
错误日志:
Error: pages.json 配置错误
Page configuration must contain "path" field.
解决方法:确保每个页面配置包含必填字段(如 path
),参考官方文档检查配置完整性。
10. 内存不足
错误日志:
[Error] Exceeded memory limit
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memoryat Map.set (<anonymous>)at Function.from (native)at Object.823 (./pages/index/index.vue:45:15)at __webpack_require__ (bootstrap:63:0)at Object.670 (./pages/index/index.vue:15:71)
常见触发场景
- 大列表渲染未使用虚拟滚动
<!-- 错误示例 -->
<view v-for="item in hugeList" :key="item.id">{{ item.content }}
</view>
- 未及时销毁大型对象
// 错误示例
data() {return {cachedData: [] // 持续增长未清理}
}
排查方法
通过Chrome开发者工具捕获内存快照
- 打开Performance面板记录内存变化
- 使用Memory面板拍摄堆快照对比
检查页面生命周期
onUnload() {// 手动释放大型变量this.hugeData = null
}
解决方案优化
- 使用虚拟列表组件
<uv-virtual-list :list="hugeList" :height="800" :itemSize="100"><template v-slot:default="{ item }"><view>{{ item.content }}</view></template>
</uv-virtual-list>
- 分页加载数据
async loadMore() {const res = await api.getList({page: this.page++,size: 20})this.list = [...this.list, ...res.data]
}
进阶调试技巧
在manifest.json中配置内存警告阈值
{"h5": {"performance": {"memoryWarningThreshold": 1024}}
}
使用uni.onMemoryWarning监听
uni.onMemoryWarning(() => {console.log('内存警告触发')// 执行内存释放操作
})
11.网络请求错误
(1).跨域问题
错误日志可:
Access to XMLHttpRequest at 'http://example.com/api' from origin 'http://localhost:8080' has been blocked by CORS policy
跨域问题通常发生在开发环境下,因为浏览器会阻止不同源的请求。解决方案包括在服务器端配置CORS头部,或使用本地代理服务器绕过跨域限制。
(2).404接口路径错误
错误日志:
GET http://example.com/api 404 (Not Found)
这类错误通常是由于接口路径拼写错误或服务器端未正确配置路由导致。检查接口路径是否正确,确保服务器端已正确部署相关接口。
(3).400参数格式错误
错误日志:
POST http://example.com/api 400 (Bad Request)
400错误通常表示请求参数格式不正确。检查请求头中的Content-Type
是否与数据格式匹配,例如application/json
或application/x-www-form-urlencoded
。确保请求体中的数据格式与服务器端要求一致。
(4).500服务器端错误
GET http://example.com/api 500 (Internal Server Error)
500错误表示服务器端处理请求时发生了内部错误。检查服务器端日志以获取更详细的错误信息,确认服务器端代码是否存在问题。
(6).网络连接问题
错误日志:
Failed to load resource: net::ERR_CONNECTION_REFUSED
这类错误通常表示客户端无法连接到服务器。检查服务器是否正常运行,网络连接是否稳定,以及是否有防火墙或安全组规则阻止了连接。
UniApp中的网络请求示例
以下是一个简单的UniApp网络请求示例,使用uni.request
方法:
uni.request({url: 'http://example.com/api',method: 'GET',data: {key1: 'value1',key2: 'value2'},header: {'Content-Type': 'application/json'},success: (res) => {console.log('请求成功:', res.data);},fail: (err) => {console.error('请求失败:', err);}
});
错误处理建议
在UniApp中,建议对所有网络请求进行错误处理,包括超时设置和异常捕获。例如:
uni.request({url: 'http://example.com/api',method: 'POST',timeout: 5000,data: {key: 'value'},success: (res) => {if (res.statusCode === 200) {console.log('请求成功:', res.data);} else {console.error('服务器返回错误:', res.statusCode);}},fail: (err) => {console.error('请求失败:', err);}
});
12. TypeScript 类型错误
(1).类型不匹配错误
error TS2322: Type 'string' is not assignable to type 'number'.
let age: number = "25";
- 原因:变量
age
被声明为number
类型,但赋值为字符串"25"
。 - 解决方法:确保赋值类型与声明类型一致,例如改为
let age: number = 25;
。
(2).缺少必要属性
error TS2741: Property 'name' is missing in type '{ age: number }' but required in type 'Person'.
interface Person {name: string;age: number;
}
const user: Person = { age: 30 };
- 原因:
Person
接口要求name
属性,但对象user
未提供。 - 解决方法:补全必要属性,例如
const user: Person = { name: "Alice", age: 30 };
。
(3).函数参数类型不匹配
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
function square(num: number): number {return num * num;
}
square("10");
- 原因:函数
square
需要number
类型参数,但调用时传入了字符串"10"
。 - 解决方法:传入正确的类型,例如
square(10)
。
(4).未识别的属性
error TS2322: Type '{ id: number; title: string; published: boolean; }' is not assignable to type 'Book'.
Object literal may only specify known properties, and 'published' does not exist in type 'Book'.
interface Book {id: number;title: string;
}
const book: Book = { id: 1, title: "TS Guide", published: true };
- 原因:
Book
接口未定义published
属性,但对象字面量中包含了该属性。 - 解决方法:移除多余属性或扩展接口定义。
错误排查通用步骤
- 查看完整错误日志,定位具体文件和行号
- 清理项目后重新编译(删除
unpackage
和node_modules
) - 对比官方模板检查基础配置
- 分平台编译缩小问题范围(如仅 H5 或仅 App)
二、处理跨域问题的方法?
1.配置本地开发服务器代理
在项目的 manifest.json
文件中配置 h5
的 devServer
选项,通过代理解决跨域问题
"h5": {"devServer": {"proxy": {"/api": {"target": "http://your-api-domain.com","changeOrigin": true,"pathRewrite": {"^/api": ""}}}}
}
2.使用后端设置 CORS 头
在后端服务中设置允许跨域的响应头,确保前端可以正常访问。常见的 CORS 头设置如下:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
3.使用 JSONP 请求
对于仅支持 GET 请求的接口,可以使用 JSONP 方式绕过跨域限制。uniapp 中可以通过 uni.request
的 dataType
设置为 jsonp
实现:
uni.request({url: 'http://your-api-domain.com/api/data',dataType: 'jsonp',success: (res) => {console.log(res.data);}
});
4.使用云函数中转请求
通过 uniapp 的云开发功能,将请求发送到云函数,再由云函数转发到目标接口。这种方式可以避免前端直接跨域请求。
// 云函数代码(如腾讯云)
const cloud = require('wx-server-sdk');
cloud.init();
const axios = require('axios');exports.main = async (event, context) => {const res = await axios.get('http://your-api-domain.com/api/data');return res.data;
};
5.生产环境使用 Nginx 反向代理
在生产环境中,可以通过 Nginx 配置反向代理解决跨域问题。
location /api {proxy_pass http://your-api-domain.com;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;
}
注意事项
- 本地开发时优先使用代理方案,避免修改后端代码。
- 生产环境确保后端配置了合适的 CORS 头或使用反向代理。
- JSONP 仅适用于 GET 请求,且需要后端支持。
三、如何捕获并处理全局错误?
1.使用 onError
生命周期钩子
在 App.vue
的 onLaunch
中,通过 uni.onError
监听全局 JavaScript 错误。适合捕获未被 try-catch
处理的异常:
export default {onLaunch() {uni.onError((error) => {console.error('全局错误:', error);// 上报错误到服务器uni.request({url: 'https://api.example.com/log',method: 'POST',data: { error: error.stack }});});}
}
2.监听 UnhandledRejection
(Promise 错误)
通过 window.addEventListener
捕获未处理的 Promise 异常:
window.addEventListener('unhandledrejection', (event) => {console.error('未处理的Promise错误:', event.reason);event.preventDefault(); // 阻止默认控制台报错
});
3.封装请求拦截器
在公共请求库中统一处理接口错误
function request(options) {return new Promise((resolve, reject) => {uni.request({...options,success: (res) => {if (res.statusCode !== 200) {reject(new Error(`请求失败: ${res.statusCode}`));} else {resolve(res.data);}},fail: (err) => {reject(err);}});}).catch(err => {console.error('请求异常:', err);throw err; // 继续抛出以供业务层处理});
}
错误处理的最佳实践
分类处理错误
- 客户端错误:如网络请求失败,提示用户重试。
- 服务端错误:如 500 状态码,记录日志并反馈给运维。
- 代码逻辑错误:如 undefined 变量,开发阶段应通过 ESLint 提前拦截。
错误上报机制
集成 Sentry 或自建日志服务,关键代码示例:
uni.onError((err) => {sentry.captureException(err); // Sentry上报
});
用户友好提示
在捕获错误后,使用 uni.showToast
避免直接暴露原始错误信息:
uni.showToast({title: '操作失败,请稍后重试',icon: 'none'
});
注意事项
- 小程序限制:部分平台(如微信小程序)无法捕获全部全局错误,需结合平台 API 补充。
- 异步错误:
setTimeout
或Promise
中的错误需单独处理,无法被onError
捕获。 - 生产环境调试:建议关闭详细错误提示,仅保留必要日志。
四、小程序白屏
检查网络连接
确保用户的网络连接稳定,弱网或断网可能导致资源加载失败。可以通过监听网络状态变化,提示用户检查网络。
wx.onNetworkStatusChange(function(res) {if (!res.isConnected) {wx.showToast({ title: '网络不可用', icon: 'none' });}
});
优化代码包体积
代码包体积过大会导致加载时间过长甚至白屏。通过分包加载、移除未使用的代码或资源来减小体积。在app.json
中配置分包:
{"subPackages": [{"root": "packageA","pages": ["pages/cat", "pages/dog"]}]
}
预加载关键资源
在onLoad
生命周期中提前请求关键数据,避免渲染阻塞。使用wx.request
预加载数据:
Page({onLoad() {wx.request({url: 'https://api.example.com/data',success: (res) => { this.setData({ keyData: res.data }); }});}
});
启用骨架屏
在数据加载完成前展示骨架屏,提升用户体验。通过wx:if
控制骨架屏与内容的切换:
<view wx:if="{{isLoading}}"><!-- 骨架屏结构 -->
</view>
<view wx:else><!-- 实际内容 -->
</view>
检查页面路由堆栈
页面路由层级过深可能导致内存不足。避免不必要的navigateTo
,使用redirectTo
替换不需要返回的页面:
wx.redirectTo({ url: '/pages/home/index' });
监控异常并上报
通过onError
捕获全局错误,结合wx.reportMonitor
上报白屏相关信息:
App({onError(err) {wx.reportMonitor('white_screen', 1);console.error('全局错误:', err);}
});
兼容性处理
检查基础库版本,过低版本可能导致渲染异常。在app.json
中设置最低支持版本:
{"envVersion": "develop","libVersion": "2.15.0"
}
内存管理优化
避免在data
中存储过大对象,及时清理定时器和事件监听。在onUnload
中释放资源:
Page({onUnload() {clearInterval(this.timer);this.eventEmitter.off();}
});