小程序 app 不支持mockjs拦截 h5 可以
本文通过匹配url 返回json数据 json可以mock
uni.request promise插件 通用轻量级api接口网络请求(支持拦截器) - DCloud 插件市场
建目录mock
对url 进行匹配,调用相应的方法返回json数据,支持路径参数 pathvariable 如 get baidu.com/:id。 若未匹配到则走网络请求
mockRequest.js
/**
- version 1.0.0
*/
class MockRequest {
constructor(config = {}) {
// {url,fun}
this.urlListener = [];
this.request = {}
this.config = {};
this.config.baseUrl = config.baseUrl? config.baseUrl: '';
this.config.dataType = config.dataType? config.dataType: 'json';
this.config.responseType = config.responseType? config.responseType: 'text';
this.config.header = config.header? config.header: {};
this.reqInterceptors = null;
this.resInterceptors = null;
this.interceptors = {
request: fn => {
this.reqInterceptors = fn;
},
response: fn => {
this.resInterceptors = fn;
}
}
}
async get(url, config = {}) {
return this._request('get', url, config);
}
async post(url, config = {}) {
return this._request('post', url, config);
}
async put(url, config = {}) {
return this._request('put', url, config);
}
async delete(url, config = {}) {
return this._request('delete', url, config);
}
/**
- 注册url
- @param {Object} url 访问对象
- @param {Object} fun 绑定的方法
*/
registUrl(url,fun){
this.urlListener.push({url,fun})
}
setConfig(config = {}) {
this.config = this._deepCopy(this._merge(this.config, config));
}
getConfig() {
return this.config;
}
setRequest(request = {}) {
this.request = request;
}
getRequest() {
return this.request;
}
_request(method, url, config) {
// 匹配url
let reqUrl = method+" "+url;
if(reqUrl.indexOf("?")!=-1){
reqUrl = reqUrl.substr(0,reqUrl.indexOf("?"));
}
let matchUrl;
let matchFun;
console.log('mock url: '+url,this.urlListener);
for (var i = 0; i < this.urlListener.length; i++) {
let urlStr = this.urlListener[i].url
if(!urlStr.startsWith(method)){
continue;
}
// 匹配路径变量 只能匹配一个 如: "get baidu.com/:id" "get baidu.com/:id/ab"
if(urlStr.indexOf(":")!=-1){
let pathVar = urlStr.match(/:\w+/);
let urlReg = urlStr.replace(pathVar,"\\w+");
let matchStr = reqUrl.match(urlReg);
if(matchStr){
matchUrl = urlStr;
matchFun = this.urlListener[i].fun;
}
}else if(urlStr===reqUrl){
matchUrl = urlStr;
matchFun = this.urlListener[i].fun;
}
}
console.log('mock request url: '+matchUrl+' ==> '+method +' '+url)
if(matchFun){
//模拟异步请求数据
return new Promise(resolve=>{
setTimeout(()=>{
let data = matchFun.call(method,url,config);
resolve(data);
}, 500)
})
}else{
if(this.request && this.request._request){
this.request._request(method,url,config);
}else{
console.log('non request send.')
}
}
}
_formatUrl(baseUrl, url) {
if (!baseUrl) return url;
let formatUrl = '';
const baseUrlEndsWithSlash = baseUrl.endsWith('/');
const urlStartsWithSlash = url.startsWith('/');
if (baseUrlEndsWithSlash && urlStartsWithSlash) {
formatUrl = baseUrl + url.substring(1);
} else if (baseUrlEndsWithSlash || urlStartsWithSlash) {
formatUrl = baseUrl + url;
} else {
formatUrl = baseUrl + '/' + url;
}
return formatUrl;
}
_merge(oldConfig, newConfig) {
let mergeConfig = this._deepCopy(oldConfig);
if (!newConfig || !Object.keys(newConfig).length) return mergeConfig;
for (let key in newConfig) {
if (key !== 'header') {
mergeConfig[key] = newConfig[key];
} else {
if (Object.prototype.toString.call(newConfig[key]) === '[object Object]') {
for (let headerKey in newConfig[key]) {
mergeConfig[key][headerKey] = newConfig[key][headerKey];
}
}
}
}
return mergeConfig;
}
_deepCopy(obj) {
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object') {
result[key] = this._deepCopy(obj[key]);
} else {
result[key] = obj[key];
}
}
}
return result;
}
}
if (!global.$mockRequest) {
global.$mockRequest = new MockRequest();
}
export default global.$mockRequest;
userMock.js
模块mock 指定 url function
function getUserInfo(method,url,config){
let data = {"success":true};
return JSON.stringify(data)
}
export default {
'get /userInfo': getUserInfo
}
index.js
加载各个模块的mock
import mockRequest from '@/mock/mockRequest.js'
import userMock from '@/mock/userMock.js'
function registMock(obj){
for(let key in userMock){
mockRequest.registUrl(key,userMock[key])
}
}
registMock(userMock);
export default mockRequest
main.js 中指定mockRequest
import mockRequest from './mock/mockRequest.js'
// 加载mock
import mock from './mock/index.js'
// mock拦截 拦截失败走request
mockRequest.setRequest(request);
Vue.prototype.$request = mockRequest;
import Vue from 'vue'
import store from './store'
import App from './App'
import request from './common/request/request.js'
import mockRequest from './mock/mockRequest.js'
// 加载mock
import mock from './mock/index.js'
import Json from './Json' //测试用数据
/**
- 因工具函数属于公司资产, 所以直接在Vue实例挂载几个常用的函数
- 所有测试用数据均存放于根目录json.js
- css部分使用了App.vue下的全局样式和iconfont图标,有需要图标库的可以留言。
- 示例使用了uni.scss下的变量, 除变量外已尽量移除特有语法,可直接替换为其他预处理器使用
*/
const msg = (title, duration=1500, mask=false, icon='none')=>{
//统一提示方便全局修改
if(Boolean(title) === false){
return;
}
uni.showToast({
title,
duration,
mask,
icon
});
}
const json = type=>{
//模拟异步请求数据
return new Promise(resolve=>{
setTimeout(()=>{
resolve(Json[type]);
}, 500)
})
}
const prePage = ()=>{
let pages = getCurrentPages();
let prePage = pages[pages.length - 2];
// #ifdef H5
return prePage;
// #endif
return prePage.$vm;
}
// 全局配置
request.setConfig({
baseUrl: 'https://www.cookegc.com', // 此为测试地址,需加入到域名白名单,或者更改为您自己的线上地址即可
dataType: 'json', // 可删除,默认为json
responseType: 'text', // 可删除,默认为text
// 设置请求头,支持所有请求头设置,也可不设置,去掉header就行
header: {
'token': 'token from global',
'content-type': 'application/json'
}
})
// 设置请求拦截器
request.interceptors.request(config => {
// 配置参数和全局配置相同,此优先级最高,会覆盖在其他地方的相同配置参数
// 追加请求头,推荐
// config.header['content-type'] = 'application/json';
// config.header.token = 'token from interceptors';
let token = uni.getStorageSync('token');
// 覆盖请求头
config.header = {
// 'content-type': 'application/json',
'token': token
}
// return false; // 终止请求
// return Promise.reject('error from request interceptors'); // 向外层抛出错误,用catch捕获
return config; // 返回修改后的配置,如未修改也需添加这行
})
// 设置响应拦截器
request.interceptors.response(res => {
// 接收请求,执行响应操作
// 您的逻辑......
// return false; // 阻止返回,页面不会接收返回值
// return {message: '自定义值,来自拦截器'}; // 返回您自定义的值,将覆盖原始返回值
// return Promise.reject('error from response interceptors') // 向外层抛出错误,用catch捕获
return res; // 原样返回
})
// mock拦截 拦截失败走request
mockRequest.setRequest(request);
Vue.prototype.$request = mockRequest;
// 挂载到全局vue实例上,在页面中可以使用this.$request调用request实例下相应方法
// Vue.prototype.$request = request;
Vue.config.productionTip = false
Vue.prototype.$fire = new Vue();
Vue.prototype.$store = store;
Vue.prototype.$api = {msg, json, prePage};
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
使用demo
this.$request.get("/userInfo").then(res=>{
console.log('index.vue userInfo',res);
})