浅析 uniapp(Vue) 的接口封装方法

浅析 uniapp(Vue) 的接口封装方法

本文将详细讲解封装思路,通过对接口请求进行封装,实现接口引入即用,减少了请求复杂的属性参数,更加关注数据与业务本身。

config - 请求地址及相关参数配置

在 config 文件夹中配置好动态域名,对不同环境进行配置,方便前端开发时的调试与部署。

develop.js(开发)

配置开发环境:有多个开发环境时,可以根据开发的需要切换到不同的接口进行调试,定义完后抛出。

const ENV_TYPE = {
    
    
	// baseUrl: 'https://120.120.120.1/', // 调试环境1
    // baseUrl: 'https://120.120.120.2/', // 调试环境2
    // baseUrl: 'https://120.120.120.3/', // 调试环境3
    baseUrl: 'https://120.120.120.4/', // 调试环境4
}
module.exports = ENV_TYPE

trial.js(体验)

配置体验版服务器的地址,小程序上必须先发布体验版再发布测试版

const ENV_TYPE = {
    
    
	baseUrl: 'https://test.com/', // 体验服务器地址
}
module.exports = ENV_TYPE

release.js(正式)

配置正式服务器地址

const ENV_TYPE = {
    
    
	baseUrl: 'https://formal.com/',
}
module.exports = ENV_TYPE

urlConfig.js(判断当前环境)

通过对环境的检测,判断当前所属的是什么环境,动态切入请求地址,减少上传时的操作步骤。

现在我们需要了解的是如何知道当前所属的环境。由下文可知,我们可以基于 process.env.ENV_PATHuni.getAccountInfoSync() 获取当前所属的环境动态配置

uni-app 可通过 process.env.NODE_ENV 判断当前环境是开发环境还是生产环境。一般用于连接测试服务器或生产服务器的动态切换。

  • 在 HBuilderX 中,点击“运行”编译出来的代码是开发环境,点击“发行”编译出来的代码是生产环境
  • cli 模式下,是通行的编译环境处理方式。

uni.getAccountInfoSync() 获取当前帐号信息,可以返回小程序的Appid。如果使用了微信小程序的云端插件,还可以反馈插件的id和版本

  • miniProgram 的结构:

    属性 类型 说明
    appId string 小程序 appId
    envVersion string 小程序 当前环境版本:developtrialrelease
    version string 版本号

动态添加成功后,抛出 baseUrl 给接口文件引入

/**
 * 配置动态化域名,外部js引用此文件process.env.NODE_ENV
 */
let path = process.env.ENV_PATH == undefined ? require('../config/develop') : require(process.env.ENV_PATH)

// #ifdef MP-WEIXIN
// ---------------- 根据微信开发环境配置请求地址 --------------------
// 获取当前帐号信息
const accountInfo = uni.getAccountInfoSync();
console.log(accountInfo)
// env类型 develop:开发版、trial:体验版、release:正式版
const envWx = accountInfo.miniProgram.envVersion;
if (envWx === 'release') {
    
    
	path = require('../config/release.js')
} else if(envWx === 'trial') {
    
    
	path = require('../config/trial.js')
} else if(envWx === 'develop') {
    
    
	path = require('../config/develop.js')
}
// #endif

const baseUrl = path.baseUrl
module.exports = {
    
    
	baseUrl
}

networking - 接口请求配置

在该文件夹内我们对接口请求进行封装,对请求方式简化,专注于数据和业务。

networkRequestManage.js

对uniapp请求进行封装,设置登录请求和上传图片等公共请求接口。

/**
 * 网络请求管理,二次封装
 */

/** 请求信息格式
{
  apiName: 'url',
  params: {
    'key1': 'value1',
    'key1': 'value2',
  },
  success: e=> {

  },
  fail: e=> {

  }
} */

// 状态码
import hsCode from '../config/statusCode.js'
// 导入当前域名地址
import urlConfig from '@/config/urlConfig.js'
// 导入缓存
import storage from "@/config/storage.js"

// 调用超时的是时候,保存调取接口传入参数的参数
let requestInfoData = ''
let requestMethod = ''

/**
 * 请求数据
 * @url: 请求路径
 * @params:请求参数(数据类型,对象)
 * method: post get
 * success:成功回调函数
 * fail:失败回调函数
 */
function request(apiName, params = {
     
     }, method, success, fail) {
    
    
	const token = storage.getToken()
	var headersParam = {
    
    
		'X-Requested-With': 'XMLHttpRequest',
		"Accept": "application/json",
		"Content-Type": "application/json; charset=UTF-8;",
		"Accept-Encoding": ''
	}
	// token为空
	if (token != '' || token != undefined || token != null) {
    
    
		headersParam['Authorization'] = 'Bearer ' + token
	}
	console.log(urlConfig.baseUrl + apiName)
	console.log('请求参数---->' + JSON.stringify(params))
	// 发送请求
	uni.request({
    
    
		url: urlConfig.baseUrl + apiName,
		data: params,
		header: headersParam,
		method: method,
		success: function(res) {
    
    
			if (res.data.code === hsCode.SUCCESS) {
    
    
				success && success(res.data)
				// token过期
			} else if (res.data.code === hsCode.DENY) {
    
    

			} else {
    
    
				if (fail) {
    
    
					fail(res.data.msg)
				} else {
    
    
					uni.showToast({
    
    
						title: res.data.msg,
						icon: 'none'
					})
				}
			}
		},
		fail: function(res) {
    
    
			fail && fail('请检查网络')
		},
	})
}

// 微信登录获取 sessionKey
/**
 * 重新登录
 * @success: 成功回调函数
 * @params: 额外参数
 * @isAgin:超时重新请求当前数据(false不请求,true请求)
 */
function onLogin({
     
     
	success,
	params = {
     
     },
	isAgin = false
} = {
     
     }) {
    
    
	// 判定对内或对外
	uni.login({
    
    
		success(res) {
    
    
			params['js_code'] = res.code
			console.log(res)
			uni.request({
    
    
				url: urlConfig.baseUrl + 'login',
				data: params,
				header: {
    
    
					'content-type': 'application/json' // 默认值
				},
				success(res) {
    
    
					// 成功
					if (res.statusCode === 200) {
    
    
						if (res.data.code === hsCode.successCode) {
    
    
							const data = res.data.data
							if (isAgin) {
    
    
								if (requestMethod === 'GET') {
    
    
									requestWithGet(requestInfoData)
								} else if (requestMethod ===
									'POST') {
    
    
									requestWithPost(requestInfoData)
								}
							}
							success && success(res)
						} else {
    
    
							console.log('wx.login:fail ' + res.data.msg)
						}
					} else {
    
    
						console.log('wx.login:fail ' + res.errMsg)
					}
				},
				fail(res) {
    
    
					console.log('wx.login:fail ' + res.errMsg)
					wx.showToast({
    
    
						title: '请检查网络',
						icon: 'none'
					})
				}
			})
		},
		fail(res) {
    
    
			// 失败
			console.log(res)
			uni.showToast({
    
    
				title: '请检查网络状态',
				icon: 'none'
			})
		}
	})
}

// 深拷贝对象
function deepCopy(obj) {
    
    
	var result = Array.isArray(obj) ? [] : {
    
    };
	for (var key in obj) {
    
    
		if (obj.hasOwnProperty(key)) {
    
    
			if (typeof obj[key] === 'object') {
    
    
				result[key] = deepCopy(obj[key]); //递归复制
			} else {
    
    
				result[key] = obj[key];
			}
		}
	}
	return result;
}

/**
 * DELETE请求
 */
export function requestWithDelete(requestInfo) {
    
    
	requestInfoData = deepCopy(requestInfo)
	requestMethod = 'DELETE'
	request(requestInfo.apiName, requestInfo.params, "DELETE", requestInfo.success, requestInfo.fail);
}

/**
 * put请求
 */
export function requestWithPut(requestInfo) {
    
    
	requestInfoData = deepCopy(requestInfo)
	requestMethod = 'PUT'
	request(requestInfo.apiName, requestInfo.params, "PUT", requestInfo.success, requestInfo.fail);
}

/**
 * post请求
 */
export function requestWithPost(requestInfo) {
    
    
	requestInfoData = deepCopy(requestInfo)
	requestMethod = 'POST'
	request(requestInfo.apiName, requestInfo.params, "POST", requestInfo.success, requestInfo.fail);
}

/**
 * get请求
 */
export function requestWithGet(requestInfo) {
    
    
	requestInfoData = deepCopy(requestInfo)
	requestMethod = 'GET'
	request(requestInfo.apiName, requestInfo.params, "GET", requestInfo.success, requestInfo.fail);
}

// 上传图片
/**
 * 上传图片传参
 * options: {
 *  image: [],        必须,图片数据 string[]
 *  params: {},       必须,接口参数
 *  success: ()=>{},  成功回调
 *  fail: ()=>{},     失败回调
 * }
 */
export function uploadImage(options) {
    
    
	console.log('请求参数---->' + JSON.stringify(options.params))
	let url = urlConfig.baseUrl + 'api/upload'
	if (typeof options.image === 'undefined' || options.image.length === 0) {
    
    
		requestWithPost({
    
    
			url,
			params: options.params,
			success: data => {
    
    
				wx.hideLoading()
				options.success && options.success(data)
			},
			fail(res) {
    
    
				wx.hideLoading()
				options.fail && options.fail(res)
			}
		})
		return
	}
	let callUploadApi = 0

	for (let i = 0; i < options.image.length; i++) {
    
    
		if (typeof options.params.sortNum === 'undefined') options.params.sortNum = 0
		options.params.Sort = options.params.sortNum + (i + 1)
		// setTimeout(() => {
    
    
		wx.uploadFile({
    
    
			url: url + arugment, //仅为示例,非真实的接口地址
			filePath: options.image[i],
			name: 'file',
			header: {
    
    
				'content-type': 'multipart/form-data',
				"Cookie": "ASP.NET_SessionId=" + wx.getStorageSync("sessionId")
			},
			formData: options.params,
			success(res) {
    
    
				wx.hideLoading()
				const data = JSON.parse(res.data)
				callUploadApi++
				if (callUploadApi === options.image.length) {
    
    
					options.success && options.success(data)
				}
			},
			fail(res) {
    
    
				wx.hideLoading()
				options.fail && options.fail(res)
			}
		})
	}
}

module.exports = {
    
    
	requestWithGet,
	requestWithPost,
	requestWithPut,
	requestWithDelete,
}

publicInferface.js

进行模块化的接口管理,你当前接口属于哪个模块,你就放在哪个模块里面。这样更方便对接口进行管理,后期也更好维护。该文件内的接口为基本模拟,实际开发按需添加接口即可。

// 公共接口调用
// 调用封装接口的文件,下面的所有请求都使用封装好的接口
import hs from './networkRequestManage'
import hsCode from '../config/statusCode.js'
import storage from '../config/storage'
import urlConfig from '@/config/urlConfig.js'

/**
 * GET接口请求
 */
function getTranslation(key) {
    
    
	return new Promise((resolve, reject) => {
    
    
		hs.requestWithPost({
    
    
			apiName: 'api/common/GetTranslation',
            params: {
    
     // 没有参数可以直接不传参
				key
			},
			success: data => {
    
    
				resolve(data)
			},
			fail: res => {
    
    
				reject(res)
			}
		})
	})
}

/**
 * POST接口请求
 */
function postTranslation(params) {
    
    
	return new Promise((resolve, reject) => {
    
    
		hs.requestWithGet({
    
    
			apiName: 'api/common/PostTranslation',
            params,
			success: data => {
    
    
				resolve(data)
			},
			fail: res => {
    
    
				reject(res)
			}
		})
	})
}

/**
 * PUT接口请求
 */
function putTranslation(key) {
    
    
	return new Promise((resolve, reject) => {
    
    
		hs.requestWithPut({
    
    
			apiName: 'api/common/PutTranslation',
            params: {
    
    
				key:key,
			},
			success: data => {
    
    
				resolve(data)
			},
			fail: res => {
    
    
				reject(res)
			}
		})
	})
}

/**
 * DELETE接口请求
 */
function getTranslation() {
    
    
	return new Promise((resolve, reject) => {
    
    
		hs.requestWithDelete({
    
    
			apiName: 'api/common/DeleteTranslation',
			success: data => {
    
    
				resolve(data)
			},
			fail: res => {
    
    
				reject(res)
			}
		})
	})
}

// 导出接口
module.exports = {
    
    
	getTranslation,
    postTranslation,
    putTranslation,
    getTranslation,
}

main.js - 配置全局导入

在main.js中对配置文件全局导入,我们调用接口的时候就可以直接调用,而不用每次都import导入相关文件。

  • import * as publicInterface from './networking/publicInferface.js'

    导入接口 js 为下面的原型定义做准备

  • Vue.prototype.$publicInterface = publicInterface

    在vue项目main.js文件中通过上述方法,可以原型上定义它们使其在每个 Vue 的实例中可用,为后面我们在页面中的导入做准备

import App from './App'

// 公共接口
import * as publicInterface from './networking/publicInferface.js'
import storage from 'config/storage.js' // 缓存文件
import tools from 'utils/tools.js' // 工具文件

// 定义全局
Vue.prototype.$publicInterface = publicInterface
Vue.prototype.$storage = storage
Vue.prototype.$tools = tools

// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
    
    
	...App
})
app.$mount()
// #endif

// #ifdef VUE3
import {
    
    
	createSSRApp
} from 'vue'
export function createApp() {
    
    
	const app = createSSRApp(App)
	return {
    
    
		app
	}
}
// #endif

publicInferface.vue - 页面调用接口

接下来介绍页面中如何引用,在 main.js 中定义后,导入就变得很简单了。

根据在接口文档定义的参数,需要调用对应功能模块下对应函数即可。只要你在接口页面处理好了请求类型与参数传递格式,就只需要关注传递的参数。

/**
 * get请求:
 * $publicInferface:注意你在 main.js 定义的名称
 * getTranslation:注意你在 publicInferface.js 接口页面定义的函数名,一定不能重复
 */
this.$publicInferface.getTranslation(key)
	.then(e => {
    
    
    	// 最后在回调里对返回数据进行处理即可
		console.log(e)
	})
	.catch(e => {
    
    
		console.log(e)
	})

/**
 * post请求:
 * @params Object
 * 格式和get请求基本都是一样的,只有参数改变
 */
this.$publicInferface.postTranslation(params)
	.then(e => {
    
    
		console.log(e)
	})
	.catch(e => {
    
    
		console.log(e)
	})

猜你喜欢

转载自blog.csdn.net/get_404/article/details/127907543