💢第一坑来自ali云,ali云的函数计算FC产品在使用模板创建项目的过程中,如下图中的服务名和函数名每次创建都是一样的,我们很容易就按默认的创建了,但是多次创建会覆盖前一次的内容,我写好的授权接口就被覆盖了~
💘ali的产品原来也有这种低级的错误,不管你是产品设计的缺陷还是系统开发的缺陷,这都是致命的,因为正常运行的服务丢了~
💥第二坑来自WeChat,在ali云调试好的代码丢就丢了吧,我就打算还在ali云上开始重新来一遍,靠着搜索到的网站还没关掉,就写完了第二遍云上的代码,接口测试可以返回信息,但是【折】在了前端wx.config函数的校验问题上,写过的都知道文档提供了校验失败的排查过程,你要是能按这个解决了,微信开发社区就不会提5k+近似重复的问题而没有结果了~
💤写代码就应该【有始有终】我还是在本地搭建全套环境来再搞一遍试试看,请熟悉下面各个地址的快速上手文档来搭建环境~
7001
端口进行映射,7001
是eggjs项目默认端口;config.ini
配置文件并将平台提供的免费隧道键入到配置文件中,格式同:authtoken=<your authtoken>
;yarn create vite
创建一个前端项目,用着顺手就行,为的就是快~axios
来发送授权信息获取请求;<script src="[http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>](http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>)
<template>
<h3 v-if="message">{{ message }}</h3>
<h3 v-else>
点击右上角=>分享给朋友
<h5>{{ status }}</h5>
</h3>
</template>
复制代码
axios
获取/signature
接口的数据,为了避免url参数的传递可能存在编码的问题,那我们稍后在设计/signature
接口的时候url参数通过body传递来避免,授权数据拿到后就是wx.config
执行验证了~<script setup>
import { ref } from "vue";
import axios from "axios";
const message = ref("");
const status = ref("");
axios
.post(`http://t2fzbb.natappfree.cc/signature`, {
url: location.href.split("#")[0],
})
.then((res) => {
const { appId, nonceStr, signature, timestamp } = res.data;
console.log("[ res ] >", appId, nonceStr, signature, timestamp);
wx.config({
debug: true, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ["updateAppMessageShareData"], // 必填,需要使用的 JS 接口列表
});
wx.error((res) => {
message.value = res.errMsg;
});
wx.ready(() => {
wx.checkJsApi({
jsApiList: ["updateAppMessageShareData"], // 需要检测的 JS 接口列表,所有 JS 接口列表见附录2,
success: (res) => {
wx.updateAppMessageShareData({
title: "我的掘金", // 分享标题
desc: "我在掘金输出前端知识~", // 分享描述
link: "https://juejin.cn/user/3966693685871694", // 分享链接,该链接域名或路径必须与当前页面对应的公众号 JS 安全域名一致
imgUrl:
"https://p9-passport.byteacctimg.com/img/user-avatar/71ca4682501063257d8413ff726105a0~300x300.images", // 分享图标
success: function () {
status.value = "设置成功";
},
});
},
});
});
});
</script>
复制代码
最终我们要在微信开发者工具的公众台看到一堆ok就说明可以了~
🤣在开始前有一个问题,微信的各种票据都需要我们自己做缓存处理,仅在超时后再刷新,要不会遇到调用次数超限制的麻烦,服务端缓存票据我最先想到的是Redis,但是多一份配置还是挺麻烦的,后来想到的是读写文件,我在【ali云】的两次就是通过读写文件来实现的,毕竟是Demo,效率靠后呗~ 😋最后我想到的是服务运行后我可以使用全局对象来缓存数据呀,并不需要借助额外的渠道来实现,我们以前的单利模式就是在需要的时候再实例化对象的呀💗
access_token
,我会在server层做access_token
的对象缓存;ticket
,这个也会在server层做对象缓存;access_token
和ticket
,可以看到url
我们是通过body
获取的。import { Controller } from 'egg';
export default class HomeController extends Controller {
public async checkOrigin() {
const { ctx } = this;
const { signature, timestamp, nonce, echostr } = ctx.query;
const result = await ctx.service.weChat.checkSignature(
signature,
timestamp,
nonce,
);
ctx.body = result ? echostr : '';
}
public async token() {
const { ctx } = this;
ctx.body = await ctx.service.weChat.getToken();
}
public async ticket() {
const { ctx } = this;
ctx.body = await ctx.service.weChat.getTicket();
}
public async signature() {
const { ctx } = this;
const { url } = ctx.request.body;
console.log('[ url ] >', url);
ctx.body = await ctx.service.weChat.genSignature(url);
}
}
复制代码
💕需要接口微信平台发送来的signature,timestamp,nonce,在测试平台我们配置了个自定义的TOKEN,我们需要将【TOKEN, timestamp, nonce】进行sort排序后拼接成一个字符串,并使用SHA1加密算法(这里使用的crypto-js依赖)来生成我们自己的验签,将我们的生成的验签和平台发送过来的signature对比并将结果返回到Controller,并响应微信测试平台~
public async checkSignature(
signature: string,
timestamp: string,
nonce: string,
) {
const own = SHA1([ TOKEN, timestamp, nonce ].sort().join('')).toString();
return own === signature;
}
复制代码
access_token
字段不存在时就需要使用上下文对象中的curl
来发起请求获取一份新的access_token
数据;Date.now() + expires_in * 1000
得到一个失效的时间并赋值给last_time
;Date.now()
大于存储的last_time
时需要再次刷新access_token
。const cache: {
token: {
access_token: string | undefined;
expires_in: number;
last_time: number;
};
} = {
token: {
access_token: undefined,
expires_in: 0,
last_time: 0,
}
};
public async getToken() {
const { ctx } = this;
const request = async () => {
const { data } = await ctx.curl(URL_TOKEN, { dataType: 'json' });
const { access_token, expires_in } = data;
console.log('[ token data ] >', data);
cache.token = {
access_token,
expires_in,
last_time: Date.now() + expires_in * 1000,
};
};
if (!cache.token.access_token) {
console.log('[ token 还没有~ ] ');
await request();
} else {
if (Date.now() > cache.token.last_time) {
console.log('[ token 超时了 ] ');
await request();
}
}
return cache.token;
}
复制代码
🤖getTicket和getToken的缓存逻辑一致,区别在于getTicket发起请求时需要携带access_token
,其它直接看代码~
const cache: {
token: {
access_token: string | undefined;
expires_in: number;
last_time: number;
};
ticket: {
ticket: string | undefined;
expires_in: number;
last_time: number;
};
} = {
token: {
access_token: undefined,
expires_in: 0,
last_time: 0,
},
ticket: {
ticket: undefined,
expires_in: 0,
last_time: 0,
},
};
public async getTicket() {
const { ctx } = this;
const request = async () => {
const { access_token } = await this.getToken();
const { data } = await ctx.curl(URL_TICKET, {
dataType: 'json',
method: 'GET',
data: {
access_token,
},
});
const { ticket, expires_in } = data;
console.log('[ ticket data ] >', data);
cache.ticket = {
ticket,
expires_in,
last_time: Date.now() + expires_in * 1000,
};
};
if (!cache.ticket.ticket) {
console.log('[ ticket 还没有~ ] ');
await request();
} else {
if (Date.now() > cache.ticket.last_time) {
console.log('[ ticket 超时了 ] ');
await request();
}
}
return cache.ticket;
}
复制代码
jsapi_ticket
;Math.random().toString(36).substr(2, 15)
;Date.now()
;SHA1
加密并toString()
得到验签字符串就可以le~wx.config
中需要的四个参数并返回~public async genSignature(url: string) {
const { ticket: jsapi_ticket } = await this.getTicket();
const noncestr = Math.random().toString(36).substr(2, 15);
const timestamp = Date.now();
const signature = SHA1(
`jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`,
).toString();
return {
appId: APPID,
nonceStr: noncestr,
timestamp,
signature,
};
}
复制代码
💥需要调用我们的/checkOrigin
,Token字段为我们自定义的内容,和服务中验证签名时使用的一致就可以了,配置提交后会向我们的服务发起GET请求,并通过query携带参数给我们,当我们验证通过后需要将平台传递过来的随机字符返回回去代表我们验证通过~
💥这个因为我们在微信开发者工具中调试前端页面用的localhost
,所以需要将localhost
配置在这个地方~
💯代码的编写还是很容易的,就是和这种大平台沟通成本太高,每次编写都有新坑要踩,最后我将代码的配置信息剔除后上传到GitHub,需要的jym可以下载跑跑看~