H5跳转小程序
要求
1、已认证的服务号
或者 已认证的非个人主体的小程序,使用小程序云开发的静态网站托管绑定的域名下的网页
2、域名已添加至JS接口安全域名
步骤:公众号直达 - 【设置与开发】-【公众号设置】-【功能设置】-【JS接口安全域名】
域名必须是已备案
3、微信浏览器里打开
在微信浏览器里才能加载开放标签。
后端篇
1、获取Access token
请求地址
https://api.weixin.qq.com/cgi-bin/token
请求类型
GET
请求参数
{
grant_type: 'client_credential',
appid: '【公众号后台】-【设置与开发】-【基本设置】-【开发者ID(AppID)】',
secret: '【公众号后台】-【设置与开发】-【基本设置】-【开发者密码(AppSecret)】',
}
2、获取jsapi_ticket
请求地址
https://api.weixin.qq.com/cgi-bin/ticket/getticket
请求类型
GET
请求参数
{
type: 'jsapi',
access_token: '上面获取的access_token',
}
3、生成签名
变量说明
const appid = '【公众号后台】-【设置与开发】-【基本设置】-【开发者ID(AppID)】';
// 随机16位字符串,getNonceStr()是我自己封装的随机生成字符串函数。生成随机字符串网上很多,就不展开讲了
const noncestr = getNonceStr(16);
const jsapi_ticket = '上一步获取的jsapi_ticket';
// 取十位时间戳,默认时间戳是十三位
const timestamp = Math.round(new Date().getTime() / 1000).toString();
// url应该由前端传,前端没传就手动从请求头里拿
const url = requestUrl || ctx.request.header.referer;
时间戳这里是世纪大坑!很多文章都不提及过这一点,正确需要的时间戳应该是十位的
大坑2!url前端传的时候注"转码"一下,例如:’#’, ‘中文’, ‘特殊字符’
- 参与签名的字段包括有效的 jsapi_ticket(获取方式详见微信 JSSDK 文档), noncestr (随机字符串,由开发者随机生成),timestamp (由开发者生成的当前时间戳), url(当前网页的URL,不包含#及其后面部分。注意:对于没有只有域名没有 path 的 URL ,浏览器会自动加上 / 作为 path,如打开 http://qq.com 则获取到的 URL 为 http://qq.com/)。
排序变量
const string1 = `jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`;
- 对所有待签名参数按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的格式(即key1=value1&key2=value2…)拼接成字符串 string1。这里需要注意的是所有参数名均为小写字符。
加密排序后的变量string1
// sha1函数是我封装的加密。实现sha1加密网上很多,就不展开讲了
const signature = sha1(string1);
- 接下来对 string1 作 sha1 加密,字段名和字段值都采用原始值,不进行 URL 转义。即 signature=sha1(string1)。
生成后如果不放心,可以去官方验签对比一下:微信 JS 接口签名校验工具
返回给前端的格式
const result = {appid, timestamp, noncestr, signature};
return {
code: 200,
msg: 'ok',
data: result
};
完整代码
"use strict";
const Service = require('egg').Service;
const {getNonceStr} = require('../../utils/base');
const {sha1} = require('../../utils/encryption');
class WxService extends Service {
async getSignature(requestUrl) {
const {ctx, service} = this;
const appid = '【公众号后台】-【设置与开发】-【基本设置】-【开发者ID(AppID)】';
// 随机16位字符串,getNonceStr()是我自己封装的随机生成字符串函数。生成随机字符串网上很多,就不展开讲了
const noncestr = getNonceStr(16);
const jsapi_ticket = '上一步获取的jsapi_ticket';
// 取十位时间戳,默认时间戳是十三位
const timestamp = Math.round(new Date().getTime() / 1000).toString();
// url应该由前端传,前端没传就手动从请求头里拿
const url = requestUrl || ctx.request.header.referer;
const string1 = `jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`;
const signature = sha1(string1);
// console.log({appid, noncestr, jsapi_ticket, timestamp, url, string1, signature})
return {appid, timestamp, noncestr, signature};
}
}
module.exports = WxService;
前端篇
index.html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>wx_h5</title>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<p>测试</p>
<div ref="launchBtnHome" class="launchBtnHome">
<wx-open-launch-weapp id="launch-btn" username="gh_8052c0bb85ba" path="/pages/index/index.html">
<template>
<style>
.btn {
padding: 12px;
width: 200px;
height: 50px;
}
</style>
<button class="btn">打开小程序</button>
</template>
</wx-open-launch-weapp>
</div>
</body>
<script>
$(document).ready(function () {
$.get("后端API地址", function (res) {
console.log(res.data);
const { appid, timestamp, noncestr, signature } = res.data;
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appid, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature,// 必填,签名
jsApiList: ['chooseImage'], // 必填,需要使用的JS接口列表
openTagList: ['wx-open-launch-weapp'] // 使用开放标签
});
var btn = document.getElementById('launch-btn');
btn.addEventListener('launch', function (e) {
console.log('success');
});
btn.addEventListener('error', function (e) {
console.log('fail', e.detail);
});
//配置成功之后的函数,按钮生成成功
wx.ready(() => {
console.log("ready");
});
wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名
});
});
});
</script>
</html>
闲话篇
如果根据以上步骤还是报错,给几个排查方向:
- 服务号是否认证
- 是否把访问的连接加在了-JS接口安全域名
- 是否在微信浏览器里打开
- 检查url,前端打印and后端打印,两个一起看一下是否一样
- 更多的报错就要去官方文档看下了