这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

微信调用jssdk全流程详解

系统框架使用的是前后端分离,前端使用vant,后端是springboot

一、网页授权的时序图

二、公众号配置

1. 绑定域名

登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。也就是这样:

点击设置之后,弹出这样一个输入框,输入服务器所在的域名:

2:引入js文件

直接在你的页面里引入js文件就行

<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>

三、前端方法

1. 初始化方法,从后台获取基本的参数

前端进入需要扫一扫功能的页面时候,在mounted方法里面,执行微信配置getWxConfig(),此方法主要是获取jssdk所需要的参数,先检查本地缓存的是否过期,过期则请求后台获取

export function getWxConfig() {
//判断signature是否过期
if (expireSign()) {
let data = {};
data.appId = localStorage.getItem('appId');
data.timestamp = localStorage.getItem('timestamp');
data.nonceStr = localStorage.getItem('nonceStr');
data.signature = localStorage.getItem('signature');
setWxConfig(data);
} else {
//如果过期了,请求后台获取
let url = location.href.split('#')[0]; //获取锚点之前的链接,防止出现invalid signature错误
wxSign({ url: url })
.then(res => {
console.log(res);
if (res.code == 200) {
localStorage.setItem('appId', res.data.appId);
localStorage.setItem('timestamp', res.data.timestamp);
localStorage.setItem('nonceStr', res.data.nonceStr);
localStorage.setItem('signature', res.data.signature);
localStorage.setItem('expireSignTime', res.data.expireTime);
setWxConfig(res.data);
} else {
localStorage.removeItem('expireSignTime');
Toast.fail('网络故障,请退出重新加载页面');
}
})
.catch(error => {
localStorage.removeItem('expireSignTime');
Toast.fail('网络故障,请退出重新加载页面');
});
}
}

2:注入config配置

上面获取到后台的参数后,在页面使用wx.config接口注入权限验证配置

function setWxConfig(data) {
console.log(data);
wx.config({
debug: false, // true是开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.appId, // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,签名的时间戳,后台生成的
nonceStr: data.nonceStr, // 必填,签名的随机串,后台生成的
signature: data.signature, // 必填,签名,后台生成的
jsApiList: ['scanQRCode'] // 必填,需要使用的JS接口列表,scanQRCode是调用扫一扫二维码
});
wx.error(function(res) {
localStorage.removeItem('expireSignTime');
Toast.fail('网络故障,请退出重新页面');
});
}

3. 方法调用

config如果不报错,则在 wx.ready里面调用jssdk的方法

    wx.ready(function () {
wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果
success: function (res) {
let data = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
let code = codeFormat(data);
that.pointCode = code;
that.saveSinglePoint();
},
});
});

四、后端方法

1. 获取access_token和jsapi_Ticket,缓存使用了文件的方式,也支持redis等方式

/**
* 获取access_token和jsapi_ticket
**/
public AppWechatEntity getJsapiTicket() {
//logger.debug("--------------开始执行getJsapiTicket方法--------------");
//定义过期时间
AppWechatEntity appWechatEntity = new AppWechatEntity();
String accessTokenString = "";
String jsapiTicketString = "";
String jsapi_ticket = "";
String access_token = "";
jsapiTicketString = readWechatTokenFile(getJsapiTicketFilePath());
if (!StringUtils.isEmpty(jsapiTicketString)) {
appWechatEntity = JSONObject.parseObject(jsapiTicketString, AppWechatEntity.class);
long expireTime = appWechatEntity.getExpire_time();
long curTime = create_timestamp();
if (expireTime >= curTime && StrUtil.isNotEmpty(appWechatEntity.getJsapi_ticket())) {
//logger.debug("已有的jsapi_ticket=" + jsapi_ticket);
return appWechatEntity;
}
} long timestamp = create_timestamp() + 7000;//过期时间是2小时(7200s)
access_token =
getAccessTokenData("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + configBeanValue.appid + "&secret=" + configBeanValue.secret);
Map accessTokenMap = new HashMap();
accessTokenMap.put("expire_time", timestamp);
accessTokenMap.put("access_token", access_token);
accessTokenString = JSONObject.toJSONString(accessTokenMap); jsapi_ticket = getJsapiTicketData("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi");
Map jsapiTicketMap = new HashMap();
jsapiTicketMap.put("expire_time", timestamp);
jsapiTicketMap.put("jsapi_ticket", jsapi_ticket);
jsapiTicketString = JSONObject.toJSONString(jsapiTicketMap); // 写文件
try {
FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
FileUtils.writeStringToFile(new File(getJsapiTicketFilePath()), jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
//logger.debug("写入文件成功");
} catch (IOException e) {
log.debug("写文件异常:" + e.getMessage());
e.printStackTrace();
} appWechatEntity.setJsapi_ticket(jsapi_ticket);
appWechatEntity.setExpire_time(timestamp);
appWechatEntity.setAccess_token(access_token);
//logger.debug("--------------结束执行getJsapiTicket方法--------------");
return appWechatEntity;
}

2.根据jsapi_ticket获取signature

上面获取了jsapi_ticket之后,使用jsapi_ticket,noncestr,timestamp和前端传入的url组装成签名字符串,使用sha1进行加密,返回到前端

/**
* 生成signature
**/
@Override
public AppWechatEntity sign(String url) {
Map<String, String> ret = new HashMap();
String nonceStr = create_nonce_str();
String timestamp = Long.toString(create_timestamp());
String string1;
String signature = "";
//获取jsapi_ticket和过期时间
AppWechatEntity appWechatEntity = getJsapiTicket();
String jsapiTicket = appWechatEntity.getJsapi_ticket();
Long expireTime = appWechatEntity.getExpire_time();
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapiTicket +
"&noncestr=" + nonceStr +
"&timestamp=" + timestamp +
"&url=" + url;
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes(StandardCharsets.UTF_8));
signature = byteToHex(crypt.digest());
} catch (Exception e) {
e.printStackTrace();
} appWechatEntity.setAppId(configBeanValue.appid);
appWechatEntity.setExpire_time(expireTime);
appWechatEntity.setNonceStr(nonceStr);
appWechatEntity.setTimestamp(timestamp);
appWechatEntity.setSignature(signature);
return appWechatEntity;
}

3. 后端全部的代码

   /**
* 生成signature
**/
@Override
public AppWechatEntity sign(String url) {
Map<String, String> ret = new HashMap();
String nonceStr = create_nonce_str();
String timestamp = Long.toString(create_timestamp());
String string1;
String signature = "";
//获取jsapi_ticket和过期时间
AppWechatEntity appWechatEntity = getJsapiTicket();
String jsapiTicket = appWechatEntity.getJsapi_ticket();
Long expireTime = appWechatEntity.getExpire_time();
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapiTicket +
"&noncestr=" + nonceStr +
"&timestamp=" + timestamp +
"&url=" + url;
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes(StandardCharsets.UTF_8));
signature = byteToHex(crypt.digest());
} catch (Exception e) {
e.printStackTrace();
} appWechatEntity.setAppId(configBeanValue.appid);
appWechatEntity.setExpire_time(expireTime);
appWechatEntity.setNonceStr(nonceStr);
appWechatEntity.setTimestamp(timestamp);
appWechatEntity.setSignature(signature);
return appWechatEntity;
} /**
* 获取jsapi_ticket
**/
public AppWechatEntity getJsapiTicket() {
//logger.debug("--------------开始执行getJsapiTicket方法--------------");
//定义过期时间
AppWechatEntity appWechatEntity = new AppWechatEntity();
String accessTokenString = "";
String jsapiTicketString = "";
String jsapi_ticket = "";
String access_token = "";
jsapiTicketString = readWechatTokenFile(getJsapiTicketFilePath());
if (!StringUtils.isEmpty(jsapiTicketString)) {
appWechatEntity = JSONObject.parseObject(jsapiTicketString, AppWechatEntity.class);
long expireTime = appWechatEntity.getExpire_time();
long curTime = create_timestamp();
if (expireTime >= curTime && StrUtil.isNotEmpty(appWechatEntity.getJsapi_ticket())) {
//logger.debug("已有的jsapi_ticket=" + jsapi_ticket);
return appWechatEntity;
}
} long timestamp = create_timestamp() + 7000;//过期时间是2小时(7200s)
access_token =
getAccessTokenData("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + configBeanValue.appid + "&secret=" + configBeanValue.secret);
Map accessTokenMap = new HashMap();
accessTokenMap.put("expire_time", timestamp);
accessTokenMap.put("access_token", access_token);
accessTokenString = JSONObject.toJSONString(accessTokenMap); jsapi_ticket = getJsapiTicketData("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi");
Map jsapiTicketMap = new HashMap();
jsapiTicketMap.put("expire_time", timestamp);
jsapiTicketMap.put("jsapi_ticket", jsapi_ticket);
jsapiTicketString = JSONObject.toJSONString(jsapiTicketMap); // 写文件
try {
FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
FileUtils.writeStringToFile(new File(getJsapiTicketFilePath()), jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
//logger.debug("写入文件成功");
} catch (IOException e) {
log.debug("写文件异常:" + e.getMessage());
e.printStackTrace();
} appWechatEntity.setJsapi_ticket(jsapi_ticket);
appWechatEntity.setExpire_time(timestamp);
appWechatEntity.setAccess_token(access_token);
//logger.debug("--------------结束执行getJsapiTicket方法--------------");
return appWechatEntity;
} public String getAccessToken() {
//logger.debug("--------------开始执行getAccessToken方法--------------");
String access_token = "";
String accessTokenString = "";
AppWechatEntity appWechatEntity = new AppWechatEntity();
accessTokenString = readWechatTokenFile(getAccessTokenFilePath());
if (StringUtils.isNotEmpty(accessTokenString)) {
appWechatEntity = JSONObject.parseObject(accessTokenString, AppWechatEntity.class);
access_token = appWechatEntity.getAccess_token();
long expireTime = appWechatEntity.getExpire_time();
long curTime = create_timestamp();
if (expireTime >= curTime) {
//logger.debug("已有的access_token=" + access_token);
return access_token;
}
} long timestamp = create_timestamp() + 6000;//过期时间是2小时,但是可以提前进行更新,防止前端正好过期
access_token =
getAccessTokenData("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + configBeanValue.appid + "&secret=" + configBeanValue.secret);
Map accessTokenMap = new HashMap();
accessTokenMap.put("expire_time", timestamp);
accessTokenMap.put("access_token", access_token);
accessTokenString = JSONObject.toJSONString(accessTokenMap); // 写文件
try {
FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
//logger.debug("写入文件成功");
} catch (IOException e) {
log.debug("写文件异常:" + e.getMessage());
e.printStackTrace();
}
//logger.debug("新的access_token=" + access_token);
//logger.debug("--------------结束执行getAccessToken方法--------------");
return access_token;
} private String readWechatTokenFile(String filePath) {
String content = "";
try {
if (new File(filePath).exists()) {
FileReader fileReader = new FileReader(filePath, CharsetUtil.CHARSET_UTF_8);
content = fileReader.readString();
} else {
new File(filePath).createNewFile();
}
} catch (IOException e) {
log.error("读文件异常:" + e.getMessage());
e.printStackTrace();
}
return content;
} private String getAccessTokenData(String url) {
String str = "";
String result = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8);
if (StringUtils.isBlank(result))
return str;
str = parseData("access_token", "expires_in", result);
return str;
} private String getJsapiTicketData(String url) {
String str = "";
String result = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8);
if (StringUtils.isBlank(result))
return str;
str = parseData("ticket", "expires_in", result);
return str;
} private String parseData(String tokenName, String expiresInName, String data) {
String tokenConent = "";
JSONObject jsonObject = JSONObject.parseObject(data);
try {
tokenConent = jsonObject.get(tokenName).toString();
if (StringUtils.isEmpty(tokenConent)) {
log.error("token获取失败,获取结果" + data);
return tokenConent;
}
} catch (Exception e) {
log.error("token 结果解析失败,token参数名称: " + tokenName + "有效期参数名称:" + expiresInName + "token请求结果:" + data);
e.printStackTrace();
return tokenConent;
}
return tokenConent;
} private String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
} private String create_nonce_str() {
return IdUtil.simpleUUID();
} private Long create_timestamp() {
return System.currentTimeMillis() / 1000;
} private String getJsapiTicketFilePath() {
return configBeanValue.tokenpath + "/" + configBeanValue.appid + "_jsapiTicket.txt";
} private String getAccessTokenFilePath() {
return configBeanValue.tokenpath + "/" + configBeanValue.appid + "_accessToken.txt";
}

五.vue weixin-js-sdk进行微信分享

第一步:安装weixin-js-sdk

npm install weixin-js-sdk

第二步:

在assets文件下新建个common文件夹 ,然后再新建个utils.js文件

import wx from "weixin-js-sdk";

/*
* 微信分享
* 获取微信加签信息
* @param{data}:获取的微信加签
* @param{shareData}:分享配置参数
*/
export const wexinShare = (data, shareData) => {
let appId = data.appId;
let timestamp = data.timestamp;
let nonceStr = data.nonceStr;
let signature = data.signature;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature, // 必填,签名,见附录1
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function () {
//分享到朋友圈”及“分享到QQ空间”
wx.updateTimelineShareData({
title: shareData.title, // 分享标题
link: shareData.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareData.imgUrl, // 分享图标
success: function (res) {
// 设置成功
// console.log("分享成功返回的信息为:", res);
}
}) //“分享给朋友”及“分享到QQ”
wx.updateAppMessageShareData({
title: shareData.title, // 分享标题
desc: shareData.desc, // 分享描述
link: shareData.link, // 分享链接
imgUrl: shareData.imgUrl, // 分享图标
success: function (res) {
// console.log("分享成功返回的信息为:", res);;
}
}) });
wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
console.log('验证失败返回的信息:', res);
});
}

第三步:调用

import {wexinShare} from "@/common/utils.js";
//请求微信配置参数接口(获取签名),由后台给接口给
get_share(){
var that = this;
var urls = that.$qs.stringify(window.location.href.split('#')[0]); //看后台请求接口是get/post
that.$axios.post("/xxx",urls).then((res) => {
if (res.data) {
//微信加签
var obj = {
appId: res.data.appId,
nonceStr: res.data.nonceStr,
signature: res.data.signature,
timestamp: res.data.timestamp
}
//分享数据,这段主要是为了在hash模式下分享出去的链接不被浏览器截取,保证完全把链接分享出去
var shareWxLink = window.location.href.split('#')[0] + 'static/redirect.html?redirect=' + encodeURIComponent(window.location.href) + '&pid_uid=' + userinfo.uid;
// console.log('shareWxLink', shareWxLink)
let shareData = {
title: '标题', // 分享标题
link: shareWxLink,
imgUrl: 'http://xxx.jpg', // 分享图标
desc: '这里填写简介文字'
}
//引用
wexinShare(obj, that, shareData);
} else {
that.$toast('获取sdk参数失败!');
} }) }

本文转载于:

https://blog.csdn.net/m0_56961433/article/details/116135543

https://blog.csdn.net/u014678583/article/details/106024611

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--微信调用jssdk全流程详解的更多相关文章

  1. 拥有 GitHub 开源项目的小伙伴,免费申请 JetBrains 全家桶的全流程详解

    工欲善其事,必先利其器.如果您想要学习 Java.PHP.Ruby.Python.JavaScript.Objective-C..NET 中的任何一种开发技术,国际知名且屡获殊荣的 JetBrains ...

  2. 操作系统 I/O 全流程详解

    我们之前的文章提到了操作系统的三个抽象,它们分别是进程.地址空间和文件,除此之外,操作系统还要控制所有的 I/O 设备.操作系统必须向设备发送命令,捕捉中断并处理错误.它还应该在设备和操作系统的其余部 ...

  3. Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件

    封面:洛小汐 作者:潘潘 若不是生活所迫,谁愿意背负一身才华. 前言 上节我们介绍了 < Mybatis系列全解(四):全网最全!Mybatis配置文件 XML 全貌详解 >,内容很详细( ...

  4. git概念及工作流程详解

    git概念及工作流程详解 既然我们已经把gitlab安装完毕[当然这是非必要条件],我们就可以使用git来管理自己的项目了,前文也多多少少提及到git的基本命令,本文就先简单对比下SVN与git的区别 ...

  5. Python调用windows下DLL详解

    Python调用windows下DLL详解 - ctypes库的使用 2014年09月05日 16:05:44 阅读数:6942 在python中某些时候需要C做效率上的补充,在实际应用中,需要做部分 ...

  6. Sqlmap全参数详解

    sqlmap全参数详解 sqlmap是在sql注入中非常常用的一款工具,由于其开源性,适合从个人到企业,从学习到实战,各领域各阶段的应用,我们还可以将它改造成我们自己独有的渗透利器.这款工具中,大大小 ...

  7. tp6源码解析-第二天,ThinkPHP6编译模板流程详解,ThinkPHP6模板源码详解

    TP6源码解析,ThinkPHP6模板编译流程详解 前言:刚开始写博客.如果觉得本篇文章对您有所帮助.点个赞再走也不迟 模板编译流程,大概是: 先获取到View类实例(依赖注入也好,通过助手函数也好) ...

  8. C++的性能C#的产能?! - .Net Native 系列《二》:.NET Native开发流程详解

    之前一文<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATIVE初窥> 获得很多朋友支持和鼓励,也更让我坚定做这项技术的推广者,希望能让更多的朋友了解这项技术,于是先从官方 ...

  9. [nRF51822] 5、 霸屏了——详解nRF51 SDK中的GPIOTE(从GPIO电平变化到产生中断事件的流程详解)

    :由于在大多数情况下GPIO的状态变化都会触发应用程序执行一些动作.为了方便nRF51官方把该流程封装成了GPIOTE,全称:The GPIO Tasks and Events (GPIOTE) . ...

  10. 迅为4412开发板Linux驱动教程——总线_设备_驱动注册流程详解

    本文转自:http://www.topeetboard.com 视频下载地址: 驱动注册:http://pan.baidu.com/s/1i34HcDB 设备注册:http://pan.baidu.c ...

随机推荐

  1. JS leetcode 合并两个有序数组 解题分析

    壹 ❀ 引 今天做的一题是前两周博客园一粉丝在面试360时遇到的算法题,题目来自leetcode88. 合并两个有序数组,理解起来可能有些费劲,不过我尽量用图的形式给大家解释它,题目描述如下: 给你两 ...

  2. MOS 管工作原理

    浅谈MOS管的工作原理_数字IC修行者的博客-CSDN博客_mos管工作原理 一文讲明白MOS管工作原理 - 知乎 (zhihu.com) 闪存基本原理 (sohu.com)

  3. Js中RegExp对象

    Js中RegExp对象 RegExp对象表示正则表达式,是由普通字符和特殊字符也叫元字符或限定符组成的文字模板,用于对字符串执行模式匹配. 描述 创建一个RegExp对象通常有两种方式,一种是通过字面 ...

  4. MinGW 和 MSVC

    在 Winodws 上编译通常会用到这两种工具链 MinGW(Minimalist GNU for Windows) 通常用于跨平台开发,可以编译出在 Windows 系统上运行的 .exe 程序 M ...

  5. C++ sentry 如何压缩日志文件

    项目中在使用 sentry 上传事件的 attachment 函数过程中发现,附带的 log 文件是未压缩的,于是有了需求,即需要在 sentry 内部将未压缩的文件流压缩后再上传给服务器 这个需求看 ...

  6. 封装一些常用的 qt 控件

    在 qt 中需要做 toast 效果和图片 tip 效果,故开发了下面一个类 后续会继续添加一些常用的控件 tool_tip.h #include <qlabel.h> #include ...

  7. GDI快速遍历位图像素

    使用DIB部分可直接快速访问像素 例如,此测试将记事本中的所有白色像素替换为绿色像素 HDC hDCScreen = GetDC(NULL); HWND hWndDest = FindWindow(L ...

  8. 【libGDX】使用Mesh绘制立方体

    1 前言 ​ 本文主要介绍使用 Mesh 绘制立方体,读者如果对 Mesh 不太熟悉,请回顾以下内容: 使用Mesh绘制三角形 使用Mesh绘制矩形 使用Mesh绘制圆形 ​ 在绘制立方体的过程中,主 ...

  9. 【Android 逆向】【攻防世界】APK逆向

    1. apk安装到手机,提示输入flag 2. jadx打开apk 定位到checkSN方法 public boolean checkSN(String userName, String sn) { ...

  10. 以二进制文件安装K8S之部署Node服务

    概述 在Node上需要部署Docker.kubelet.kube-proxy,在成功加入Kubernetes集群后,还需要部署CNI网络插件.DNS插件等管理组件. 本节以将192.168.3.138 ...