场景
-
最近在使用uni-app开发H5移动端,跟往常一样使用axios发请求,做一些全局的请求拦截响应拦截操作
-
uni-app数据存储,uni-ui组件开发,配置axios,vuex。配置了vue.config.js文件做跨域操作
-
运行到谷歌浏览器一切正常,但是运行到微信开发者工具就开始报错,Adapter-适配器不可用,请求发不出去
-
最后经过网上一顿找发现答案都是一样,而且还没有解决问题,最后也是用了很久才解决问题
报错图--适配器"http"在buildat ObjectgetAdapter中不可用-请求根本就没有发出去
自己理解
1.很多人说axios不兼容uni-app,这种说法是比较草率的,其实通过改造,uni-app也可以兼容axios
1.axios是基于AJax上面封装一层,原理还是通过小黄人对象来发送请求
2.在微信开发者工具中,微信环境可能把小黄人底层的发送请求写法禁用了,导致请求发不出去,报错找不到
3.网上的解决方案都是说在axios引入地方main.js或者request.js中给axios写一个适配器-或者换版本
4.这种办法是没有从根本解决问题的,请求没有发出去还会报另外一个错buildURL为空找不到
错误解决-请求一样发不出去还会报另外一个错
在引入axios地方写一个适配器
// 解决uni-app Adapter为空问题
// axios.defaults.adapter = function(config) {
// return new Promise((resolve, reject) => {
// var settle = require('axios/lib/core/settle');
// var buildURL = require('axios/lib/helpers/buildURL');
// uni.request({
// method: config.method.toUpperCase(),
// url: config.baseURL + buildURL(config.url, config.params, config.paramsSerializer),
// header: config.headers,
// data: config.data,
// dataType: config.dataType,
// responseType: config.responseType,
// sslVerify: config.sslVerify,
// complete: function complete(response) {
// response = {
// data: response.data,
// status: response.statusCode,
// errMsg: response.errMsg,
// header: response.header,
// config: config
// };
// settle(resolve, reject, response);
// }
// })
// })
// }
结果
当前场景解读
1.为什么不用uni-app官网提供的uni.request(),因为它没有提供请求拦截和响应拦截,不满足。
2.uni-app使用axios做请求
2.1运行谷歌浏览器时
-
我们是node.js环境,我们需要往常一样在request.js中配置node.js基地址,请求拦截,响应拦截
-
在vue.config.js文件设置全局环境变量,uni-app官网全局文件有模板写法
-
因为是浏览器一样是需要跨域的,也要在vue.config.js中配置跨域
-
为什么使用uni-app数据储存,因为使用uni-app数据存储,原理是浏览器存储。
-
uni-app浏览器存储可以在谷歌浏览器正常使用,浏览器存储不可以在微信开发者工具中使用,不兼容
-
vue.config.js文件设置全局变量-官网全局文件中有例子
chainWebpack: config => {
config
.plugin('define')
.tap(args => {
args[0]['process.env'].VUE_APP_BASE_API = '"/dev-api"'
return args
})
}
2.2运行微信到开发者工具时
-
因为是微信开发者工具,微信环境,就没有跨域了,vue.config.js文件会失效,代理也会抛弃
-
因为微信环境不兼容axios,所以请求发不出去,还会报错-下面有解决方案
-
在微信环境中,我们request.js文件中的基地址就不能写全局变量了,而应该写字符串ip+端口
正确解决方案
1.把axios全部替换掉,不给用就不用,使用第三方包@escook/request-miniprogram和axios差不多
-
可以去npm官网搜索这个包,一直往下翻会有这个包的详细用法
-
这个方法是axios问题解决不了时候才用,我们这里不推荐-下面有axios解决方案
基本代码-在utils下建立requesthttp.js 在main.js中引入(和axios使用差不多-具体看
// 按需导入 $http 请求对象
import { $http } from '@escook/request-miniprogram'
// 将按需导入的 $http 挂载到 wx 顶级对象之上,方便全局调用
// wx这个东西是微信小程序里的顶级对象,也就是说所有页面都可以访问wx这个对象
// 所以我所有地方就可以用 wx.$http访问到请求对象了
// wx.$http = $http
// 设置基地址
$http.baseUrl = 'https://api-hmugo-web.itheima.net/api/public/v1/'
// process.env.VUE_APP_BASE_API
// 在 uni-app 项目中,可以把 $http 挂载到 uni 顶级对象之上,方便全局调用
// 小程序里wx是顶级对象,但是在uniapp中,uni才是顶级对象
uni.$http = $http
// 请求开始之前做一些事情
// 因为咱们是uniapp项目,顶级对象不叫wx,叫uni,记得把wx这个改成uni
$http.beforeRequest = function (options) {
uni.showLoading({
title: '数据加载中...',
})
}
// 请求完成之后做一些事情
$http.afterRequest = function () {
uni.hideLoading()
}
2.继续使用axios兼容微信环境-借助第三方包
2.1注意事项
-
这个方法是博主试过的,可以解决问题,一定要一步步看不要急
-
有时候uni-app和微信开发者工具会出bug,记得关闭重新打开编译
-
基于axios上面下了另外一个包,不用控制axios版本,要在axios包中补一个createError.js文件重点
2.2具体实现
2.2.1Hbuilder X中下包axios-miniprogram-adapter
npm i axios-miniprogram-adapter
2.2.2查看项目node_model中axios包下lib/core/文件包
2.2.3在request.js文件下添加以下配置
import adapter from 'axios-miniprogram-adapter'
// 设置基地址
const request = axios.create({
// 运行到浏览器时,把这一行注释回来,VUE_APP_BASE_API是在vue.config.js中配置的,官网有
// baseURL: process.env.VUE_APP_BASE_API,
// 运行到浏览器时下面一行注释掉
baseURL: 'http://127.0.0.1:8800',
// 在微信开发者工具环境中,axios,http是发不出去的,没有跨域,vue.config.js文件也是无效的
// 基于axios-miniprogram-adapter包给axios中添加一个适配器
// 运行到浏览器时,下面一行注释掉,axios时可以在浏览器中正常使用的,不需要适配器
adapter: adapter,
})
2.2.4从uni-app 运行到微信开发者工具,Hbuilder X会报一个错
2.2.5报错是说,axios-miniprogram-adapter是在引用axios中的包,axios缺少这个包找不到,可以通过点击下面报错来到相应文件夹查看
2.2.6在axios/lib/core创建一个createError.js包给axios-miniprogram-adapter使用就可以解决问题
-
来到这个目录下创建createError.js文件
-
把AxiosError.js文件内容直接复制到createError.js文件中即可
2.2.7在Hbuilder X重新把项目运行到微信开发者工具就发现没有报错,axios可以使用,请求发出去了
2.2.8request.js完整代码-仅供参考最好不要复制
import axios from 'axios'
import adapter from 'axios-miniprogram-adapter'
// 引入vuex
import store from '@/store'
// 解决uni-app Adapter为空问题-不可行解决不了
// axios.defaults.adapter = function(config) {
// return new Promise((resolve, reject) => {
// var settle = require('axios/lib/core/settle');
// var buildURL = require('axios/lib/helpers/buildURL');
// uni.request({
// method: config.method.toUpperCase(),
// url: config.baseURL + buildURL(config.url, config.params, config.paramsSerializer),
// header: config.headers,
// data: config.data,
// dataType: config.dataType,
// responseType: config.responseType,
// sslVerify: config.sslVerify,
// complete: function complete(response) {
// response = {
// data: response.data,
// status: response.statusCode,
// errMsg: response.errMsg,
// header: response.header,
// config: config
// };
// settle(resolve, reject, response);
// }
// })
// })
// }
// 设置基地址
const request = axios.create({
// 运行到浏览器时,把这一行注释回来,VUE_APP_BASE_API是在vue.config.js中配置的,官网有
// baseURL: process.env.VUE_APP_BASE_API,
// 运行到浏览器时下面一行注释掉
baseURL: 'http://127.0.0.1:8800',
// 在微信开发者工具环境中,axios,http是发不出去的,没有跨域,vue.config.js文件也是无效的
// 基于axios-miniprogram-adapter包给axios中添加一个适配器
// 运行到浏览器时,下面一行注释掉,axios时可以在浏览器中正常使用的,不需要适配器
adapter: adapter,
})
// 解决UNI-app上adapter is not a function问题
axios.defaults.adapter = function(config) {
return new Promise((resolve, reject) => {
console.log(config)
var settle = require('axios/lib/core/settle');
var buildURL = require('axios/lib/helpers/buildURL');
uni.request({
method: config.method.toUpperCase(),
url: config.baseURL + buildURL(config.url, config.params, config.paramsSerializer),
header: config.headers,
data: config.data,
dataType: config.dataType,
responseType: config.responseType,
sslVerify: config.sslVerify,
complete: function complete(response) {
response = {
data: response.data,
status: response.statusCode,
errMsg: response.errMsg,
header: response.header,
config: config
};
settle(resolve, reject, response);
}
})
})
}
// 请求拦截
request.interceptors.request.use(
config => {
console.log('store.getters.token', store.getters.token);
if (store.getters.token) {
console.log('执行了');
// config.headers['token'] = getToken()
// config.headers['tenant-id'] = getuserId()
// 建议使用uni-app数据同步存储,在谷歌浏览器可以用,但是谷歌浏览器储存在微信开发者工具用了
config.headers['token'] = uni.getStorageSync('token')
config.headers['tenant-id'] = uni.getStorageSync('tenant-id')
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截
request.interceptors.response.use(
res => {
const data = res.data
if (data.code === 200) {
// 如果响应成功,则正常给他返回数据
return data
} else {
uni.$showToast(data.message)
return Promise.reject(new Error(data.message))
}
},
// 响应错误的代码写这里
async error => {
// 打印错误拦截的信息
console.log('响应拦截error', error)
// error.response 这个是浏览器语法错误返回信息
// error.response.data 这个是接口返回错误信息 固定写法 看打印
if (error.response && error.response.data) {
// token失效携带页面参数返回登录页
if (error.response.status === 401) {
// vuex退出登录方法
} else {
console.log(error.response.data.message);
uni.$showToast('请求错误')
}
}
return Promise.reject(error)
}
)
// 把对象暴露出去
export default request
总结:
经过上面操作,axios就可以兼容uni-app和卫星开发者工具,我们只需要在运到浏览器和微信开发者工具是切换基地址配置就可以2端都适配
经过这一趟流程下来相信你也对 uni-app 使用axios发请求 运行到微信开发者工具报错 Adapter "http' is not available in the build 有了初步的深刻印象,但在实际开发中我 们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!
什么不足的地方请大家指出谢谢 -- 風过无痕