很早就了解与学习过微信小程序开发相关的技术栈与框架,小程序的账号也都已经申请过。但写过的 demo 项目也迟迟没有发布到小程序上。这主要的原因还是觉得不值得发布,加上各种审核相关的。而这次准备写一个搜题相关的小程序,也是时候实战发布一下,顺带记录下整个开发与发布过程。
在线体验:扫下图小程序二维码
小程序的源码地址:https://github.com/kuizuo/question-man
技术栈
小程序所采用的是 Taro + Vue3 + NutUI,之所以选这套技术栈,主要是想上 Vue3,而 uniapp 对 Vue3 的支持并不友好,在我的上篇文章中也有说明到,同时支持 uniapp 的 vue3 屈指可数。所以便选用了这套技术栈来进行开发。
页面设计
项目配置
项目搭建
taro init myApp
配置如下
安装完依赖,使用npm run dev:weapp
,在打开微信开发者工具,导入项目即可。
axios 封装
web 端 http 请求使用最多的库就是 axios 了,但是在小程序中使用 axios 会提示 adapter 未定义,原因是小程序不能解析 package.json 中的 browser module 等字段。
要使用 axios 的话 可以安装 axios-miniprogram 或者 taro-axios 库(我选择后者,但前者稍小 5kb),也就是会适配小程序的 axios 的 adapter,引入和使用与 axios 并不特别大的差异。以下是我封装后的代码
import axios from 'taro-axios'
import Taro from '@tarojs/taro'
import { useAuthStore } from '@/stores/modules/auth'
const showErrorToast = msg => {
Taro.showToast({
title: msg,
icon: 'none',
})
}
const instance = axios.create({
baseURL: process.env.BASE_URL,
})
instance.interceptors.request.use(
config => {
Taro.showLoading({
title: '加载中',
mask: true,
})
let token = Taro.getStorageSync('token')
if (typeof token == 'undefined') {
token = ''
}
config.headers = {
'Content-Type': 'application/json;charset=utf-8',
Authorization: token,
}
return config
},
error => {
console.log(error)
return Promise.reject(error)
},
)
// respone拦截器
instance.interceptors.response.use(
(response: any) => {
Taro.hideLoading()
if (response.data.isError) {
showErrorToast(response.data.error.message)
} else {
return response
}
},
error => {
if (error.response) {
Taro.hideLoading()
console.log('err', error)
let res = error.response.data
switch (res.code) {
case 400:
showErrorToast(res.message || '非法请求')
break
case 401:
const authStore = useAuthStore()
authStore.login()
// showErrorToast(res.message || '当前登录已过期,请重新登录')
// Taro.navigateTo({
// url: '/pages/login/index'
// })
break
case 403:
showErrorToast(res.message || '非法请求')
break
case 404:
showErrorToast(res.message || '请求资源不存在')
break
case 500:
case 502:
showErrorToast(res.message || '服务器开小差啦')
break
default:
showErrorToast(res.message || res.statusText)
}
} else {
console.log(error)
showErrorToast('请检查网络连接状态')
}
return Promise.reject(error)
},
)
export default instance
没什么好说的,和网页端基本一致。主要是加了个 wx 的 Loading 与 Toast。然后在 token 失效的时候,应该是要跳转到登录页面,但我并没有编写登录页面,而是重新调用一遍 login,达到静默登录的效果。
获取用户唯一标识(openid)
借助微信小程序能十分方便的获取到微信用户。在微信中,为了识别用户,每个用户针对每个公众号或小程序等应用会产生一个安全的 openid,开发者可以通过这个标识识别出用户。
要获取 openid 有以下几种方法(这里以 Taro 为例子,而为 wx 官方文档),具体代码可在官方文档中查看到。
Taro.login(option) | Taro 文档 (jd.com)
首先调用Taro.login()
获取 5 分钟时长的 code,然向 api.weixin.qq.com 获取 openid 代码如下
Taro.login({
success(res) {
let code = res.code
let appId = '小程序->开发管理->开发设置->开发者ID获取'
let appSecret = '小程序->开发管理->开发设置->开发者ID获取'
Taro.request({
url: 'https://api.weixin.qq.com/sns/jscode2session',
data: {
appid: appId,
secret: appSecret,
js_code: res.code,
grant_type: 'authorization_code',
},
method: 'GET',
success(res) {
console.log('openid', res.data.openid) // 得到openid
console.log('session_key', res.data.session_key) // 得到 session_key
},
})
},
})
但现在小程序是无法添加 api.weixin.qq.com 域名,所以上面的方案在小程序端失效,只能转到后端上。小程序官方有张实践图
整个步骤
1、调用wx.login 获取 code,此时也可调用 wx.getUserInfo 来获取用户数据(昵称,头像)
2、由于小程序后台授权域名无法授权微信的域名,所以需要将 code 与用户数据传入到自己的服务器上。
3、服务器后台接收到 code,后台将 appid+appsecret+code 向微信 api 服务获取用户的登录态信息(openid 与 session_key),服务器对这些登录态信息进行封装,如 session 或者 jwt 的 token 都可以(这里以 token 为例),返回给小程序端
4、小程序接收到 token 时,将其保存到本地存储上(wx.setStorage),每次携带该 token 请求向服务器发送请求。
不过如果使用云开发可以免去很多鉴权相关的,但由于数据库存储相关的,所以我是采用自建后台服务器,而后端暂不考虑开源,故具体逻辑代码就不演示了(考虑安全为主),自行编写后端 login 接口。
获取手机号
注意:只有企业小程序才可以获取用户手机号,个人小程序没有办法获取的。
在这篇文章中有说明到如何获取 5 行代码获取小程序用户手机号 | 微信开放社区 (qq.com)
所以就没有然后了(因为我肯定是个人账号)。
获取用户信息
要获取用户信息的需要调用 getUserProfile,演示代码如下
Taro.getUserProfile({
desc: '获取用户个人信息',
success: function(res) {
const userInfo = res.userInfo
console.log(res.userInfo)
}
}
要注意的是 getUserProfile 必须通过按钮来触发,而不能通过生命周期的形式,弹出授权窗口,用户可接受与拒绝。说白了就是开发者无法在用户不知情的情况下获取到用户信息(考虑到用户隐私相关的)
同时有一个小坑,getUserInfo 获取到微信用户与灰色头像
由于小程序官方调整了接口,导致 getUserInfo 无法获取正确的用户信息。详情可看 小程序登录、用户信息相关接口调整说明 | 微信开放社区 (qq.com)
一个正常的登录流程:
按理来说一般是要提供一个专门的登录页面,哪怕登录页面只有一个按钮,按钮名为一键登录。然后用户点击触发 getUserProfile 获取用户信息,如果用户拒绝则不允许使用软件,允许则进入主页,然后将用户信息保存置服务器上,以便下次用户访问时无需再次调用 getUserProfile 接口,直接从服务器上取。
而我的做法相对 比较粗略,我是直接允许用户进入首页,但当他使用搜索功能时,则判断服务器是否存有该用户的信息,如果没有,调用 getUserProfile,弹出授权框给用户选择。同时在首页的时候通过 checkSession 来判断 session 是否过期,过期则调用 wx.login 静默登录,更新登录态。(不过如果后端不判断该用户信息是否完善的话,那么是有办法直接绕过这种方式来进行调用接口了)。
数据库搭建
实际上这个小程序最主要的依赖就是数据库了,而这个数据库与传统的关系型(Mysql)和文档型(MongoDB)不同,要做到搜索引擎式的搜索。举个例子,搜索“李白”,能得到 【李白的诗风是】【李白的称呼】有关李白的字样,并且要求返回的速度快。像上面举到的两种数据库实现起来不方便,如果涉及到千万级别的数据库,将是按秒,甚至数十秒的响应速度。
而我所选择的数据库是Elasticsearch,能很轻松的实现上面的效果,并且有个很客观的响应速度。(具体实现自行了解,后端代码暂不考虑开源)
上传发布
当本地开发完毕时,点击右上角的上传,填写版本号相关以及项目备注,然后上传成功如下图
在版本管理中的开发版本可以看到刚刚上传的代码
点击提交审核后,会提示确保项目不是测试版与 Demo(否则将受到相应处罚)如下图
测试版
或者选择体验版(只有管理员与体验者的账号才可以访问),扫描体验版的二维码,即可使用微信访问项目。
审核版本
如果是要发布正式版的话,还需要填写如下表格,接着静等 1-7 天即可(可选择加急,一年一次)
等待审核完毕,实测一天内,审核版本如下
线上版本
最终提交发布,线上版本如下
至此,用户即可打开微信,通过小程序访问到该应用。