最近在开发一个基于uni-app的多端项目时,遇到了一个典型问题:H5环境下接口调用返回404错误,而同样的接口在APP和小程序环境下却能正常访问。这种情况在多端开发中其实很常见,主要原因是不同运行环境对网络请求的处理机制存在差异。
首先需要明确的是,uni-app虽然提供了跨平台开发能力,但各平台的实际运行环境差异很大:
当遇到H5接口404问题时,建议按照以下步骤排查:
提示:H5环境下的404错误90%以上都是由于代理配置不正确或请求地址拼接错误导致的,建议优先检查这两点。
在开发环境下,H5页面运行在本地服务器(通常是localhost),而接口服务通常部署在其他域名下。浏览器出于安全考虑,会阻止这种跨域请求。解决这个问题的常用方法就是配置开发服务器代理。
uni-app的H5开发服务器基于webpack-dev-server,可以在manifest.json中配置代理规则。其工作原理是:
/aps/api/store.getPage)https://xxx.com/api/store.getPage)这样,浏览器始终只与本地服务器通信,避免了跨域问题。
在manifest.json的源码视图中,找到h5配置项,添加devServer和proxy配置:
json复制"h5": {
"devServer": {
"port": 80,
"https": true,
"disableHostCheck": true,
"proxy": {
"/aps": {
"target": "https://xxx-xxx.com/",
"changeOrigin": true,
"secure": false,
"pathRewrite": {
"^/aps": "/"
}
}
}
},
"router": {
"base": "/h5/",
"mode": "hash"
}
}
关键参数说明:
port:开发服务器端口,默认8080,可自定义https:是否启用HTTPS,根据后端接口协议决定disableHostCheck:禁用主机检查,解决Invalid Host header问题proxy:代理规则配置
/aps:匹配请求路径的前缀target:目标服务器地址changeOrigin:修改请求头中的host为目标地址secure:是否验证SSL证书pathRewrite:路径重写规则路径匹配问题:
修改配置不生效:
HTTPS证书问题:
uni-app提供了条件编译能力,可以根据不同平台编写特定代码。对于接口请求,通常需要区分H5和非H5环境:
javascript复制let requestUrl = '';
// #ifdef H5
requestUrl = `/aps/api/store.${url}`;
// #endif
// #ifdef APP-PLUS || MP-WEIXIN
requestUrl = `${CONFIG.HOST2}/api/store.${url}`;
// #endif
uni.request({
url: requestUrl,
// 其他配置...
});
建议对uni.request进行统一封装,处理各平台的差异:
javascript复制// utils/request.js
const request = (options) => {
// 处理不同环境的URL
let url = options.url;
// #ifdef H5
if (!url.startsWith('/aps') && !url.startsWith('http')) {
url = `/aps${url.startsWith('/') ? '' : '/'}${url}`;
}
// #endif
// #ifndef H5
if (!url.startsWith('http')) {
url = `${CONFIG.BASE_URL}${url.startsWith('/') ? '' : '/'}${url}`;
}
// #endif
return new Promise((resolve, reject) => {
uni.request({
...options,
url,
success: (res) => {
// 统一处理响应
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res);
}
},
fail: (err) => {
reject(err);
}
});
});
};
export default request;
代理前缀选择:
路径重写策略:
^/aps:/ 直接去掉前缀^/aps/api:/api多代理配置:
如果需要代理多个服务,可以配置多个规则:
json复制"proxy": {
"/api1": {
"target": "https://service1.com",
"pathRewrite": {"^/api1": ""}
},
"/api2": {
"target": "https://service2.com",
"pathRewrite": {"^/api2": ""}
}
}
确认接口本身可用:
检查浏览器控制台:
验证代理是否生效:
/aps/api/test)检查请求地址拼接:
代理配置修改不生效:
Invalid Host header错误:
disableHostCheck: trueCORS跨域错误:
HTTPS证书错误:
secure: false(仅限开发环境)区分开发和生产配置:
API地址管理:
代理前缀处理:
建议使用.env文件管理不同环境的配置:
code复制// .env.development
VUE_APP_BASE_URL=/aps
VUE_APP_API_HOST=https://dev.example.com
// .env.production
VUE_APP_BASE_URL=/api
VUE_APP_API_HOST=https://api.example.com
然后在manifest.json中动态配置:
javascript复制const baseUrl = process.env.VUE_APP_BASE_URL;
"h5": {
"devServer": {
"proxy": {
[baseUrl]: {
"target": process.env.VUE_APP_API_HOST,
"pathRewrite": {
[`^${baseUrl}`]: "/"
}
}
}
}
}
如果需要更复杂的代理配置,可以创建vue.config.js:
javascript复制module.exports = {
devServer: {
proxy: {
'/aps': {
target: 'https://xxx.com',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/aps': '/'
}
}
}
}
};
减少代理层级:
启用压缩:
合理设置超时:
在实际项目中,我通常会创建一个proxy-config.js文件集中管理所有代理规则,然后在vue.config.js中引入。这种方式便于维护和团队协作,特别是在大型项目中效果显著。另外,建议在项目文档中详细记录代理配置规则,方便新成员快速上手。