【微信公众号开发】六、微信JS的使用

如何在页面中使用微信js。后台又该如何编写接口。本文将进行介绍。

【微信公众号开发】六、微信JS的使用

By img Microanswer Create at:Jul 5, 2019, 11:05:23 AM 

Tags: 微信js wx wxjs jsapi_ticket

如何在页面中使用微信js。后台又该如何编写接口。本文将进行介绍。


重要声明:本文章仅仅代表了作者个人对此观点的理解和表述。读者请查阅时持自己的意见进行讨论。

目录

本系列博文还包含了下面的博客:

  1. 【微信公众号开发】一、运作及配置流程简介
  2. 【微信公众号开发】二、解析微信请求及响应消息
  3. 【微信公众号开发】三、解析微信事件XML数据消息及响应
  4. 【微信公众号开发】四、公众号按钮设置及自己的微信按钮编辑器
  5. 【微信公众号开发】五、微信网页授权获取用户openId
  6. 【微信公众号开发】六、微信JS的使用(本文)
  7. 【微信公众号开发】七、微信JS需要注意的坑
  8. 【微信公众号开发】八、微信JS发起支付

一、微信JS介绍和注意事项

1、微信js介绍

但凡是做微信公众号开发,基本上逃不开对微信前端页面的开发,涉及了页面,那也必然就会涉及到使用微信js来完成一些功能了。微信js为我们提供了哪些方法?又能做些什么事情呢?下面介绍几种使用场景十分频繁的功能。

分享,很多时候用户都有分享自己认为不错的事物的习惯,如果我们不调用微信js去包装分享内容,那么用户分享出去的网页就默认显示的网页标题和网址,并附加一张页内第一张img图片。通过微信js的分享方法,我们可以设定自己想要的标题和图标,还有自定义的文案描述内容。这样就可以以更友好的方式将页面分享出去。

上传图片,在页面里常常遇到需要选择图片进行上传的场景,虽然在微信的浏览器里可以使用input type=file 来进行h5的方式选择文件,但其用户体验不够好。微信提供了一个非常便捷的且迎合微信操作习惯的选择图片的方式,这样就可以让用户选择图片的功能在微信中得到统一,这无疑会大幅提升用户体验。

菜单按钮(隐藏/显示),细心的朋友可能会发现,一个普通的页面在微信浏览器里打开后,点击右上角的菜单按钮,就可以看到许多的功能项提供给用户选择,加入我们不希望用户能对页面进行某些操作时怎么办?放心,微信也提供了相关的解决方案。我们可以调用微信提供的隐藏按钮方法,将一些按钮(例如:复制链接、在浏览器打开等)进行隐藏,这样用户就操作不到相关敏感功能了。当你要再次进行显示某按钮时,你又可以调用显示按钮方法进行显示。

关闭页面,操作完成,提示用户可以关闭了。你以为你一句 window.close() 就能搞定?那你就 图痒图森破 了。在微信里要关闭页面回到公众号界面,你需要调用微信提供的关闭方法来关闭。

支付,开发商店类的微信公众号的朋友一定知道,在页内直接发起微信支付让用户付款这个行为是多么的有必要。微信提供了支付方法供我们调用,可以方便的直接将用户的钱钱收入囊中。

其他还有许多的微信js方法提供、不过最常用的还是上面几个。

2、注意事项

你的页面要能使用微信js,先导条件是将你页面的域名设置到微信公众号后台中。在微信后台点击【公众号设置】【功能设置】即可找到微信js安全域名设置项。如果没设置完成,那么你将无法在你的页面中使用微信js。

二、开始接入

就像你在页面里引入JQuery那样简单,你就可以用相同的方法引入微信提供的js文件。微信js文件链接如下:

图1

这是截止本文编写时间最新的微信js文件地址,它支持https的访问。我使用图片展示它,是因为可能现在这已经不是最新的了。因为我希望你可以到“微信官方文档”这里去复制微信给出的最新地址。

有了地址,直接使用script标签进行引入:

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

现在,你就拥有了微信提供的各种方法。但是你只是拥有了它的身体,你还没有拥有它的心。要想正常的调用里面的各个方法,你需要先要配置微信js的使用授权。

三、配置js授权

当你引入了微信js后,它会在 window 下为你挂载 wx 这个对象。所有的方法你就要通过它进行调用。配置微信js授权也是要用它:

wx.config(option);

使用 config 方法就可以进行配置,但是其option参数是必选的一个对象。而这个对象的内容是:

{
    debug:     true, // 选填,开启调试模式,调用的所有api的返回值会在客户端alert出来,
                     // 若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,
                     // 仅在pc端时才会打印。
    appId:       '', // 必填,公众号的唯一标识
    timestamp:   '', // 必填,生成签名的时间戳
    nonceStr:    '', // 必填,生成签名的随机串
    signature:   '', // 必填,签名
    jsApiList:   []  // 必填,需要使用的JS接口列表
}

这些东西看起来复杂度可不小,为了安全起见,这些参数官方建议在后端生成,然后下发给前端使用。为什么要后台生成?

观察参数字段,其中signature是签名,这个签名来头可不小,它是一个sha1的数据签名,而签名数据源就需要下面的东西:

  1. noncestr: 随机字符串
  2. jsapi_ticket: js票据
  3. timestamp: 时间戳
  4. url: 当前页面url

其中jsapi_ticket是微信提供的API接口拿到的,所以此数据最优雅就是在后端获取,既然这个在后端获取,那后端干脆就顺便把上边整个option参数体全部组建好,直接返回给前端,那么前端config的事情就变得有趣起来。

四、编写后台接口

在我们之前的两篇文章【微信公众号开发】一、运作及配置流程简介 以及【微信公众号开发】二、解析微信请求及响应消息 中建立的WeChatController类中新增一个方法,用于方便获取微信js配置:

@Controller
@RequestMapping("/wechat")
public class WeChatController {

    /* 之前的代码。 */
    /* 为节省篇幅,此处省略。 */

    @RequestMapping("/getWxJsCfg")
    @RequestBody
    public String getWxjsCfg(HttpServletRequest request) throws Exception {
        return null;
    }
}

现在我们需要完善getWxjsCfg 来生成我们微信js需要的参数。

1、获取 jsapi_ticket

使用微信API即可方便的获取到jsapi_ticket,接口地址为:

<!-- 接口地址 -->
https://api.weixin.qq.com/cgi-bin/ticket/getticket

<!-- 参数列表 -->
access_token: ACCESS_TOKEN
type: 写死值:"jsapi"

使用 GET 方法请求这个地址即可获取到结果, 不过其中 ACCESS_TOKEN 需要注意,这也需要调用微信API获取,关于 ACCESS_TOKEN 的获取,请参考:《【微信公众号开发】四、公众号按钮设置及自己的微信按钮编辑器》 文中第一节的内容。接下来继续完善接口代码:

@RequestMapping("/getWxJsCfg")
@RequestBody
public String getWxjsCfg(HttpServletRequest request) throws Exception {
    // 先获取必须的参数。
    // 通常传递当前页面的url。
    String url = request.getParameter("url");

    // 获取 jsapi_ticket
    String ticket = Util.getCache("ticket"); // 先尝试从缓存获取。
    if (Util.isEmpty(ticket)) {
        // 缓存里没有获取到数据。则请求微信api获取。

        // 构建参数并请求
        Map<String, String> param = new HashMap<>();
        param.put("access_token", "ACCESSTOKEN的值");
        param.put("type", "jsapi");
        String result = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", param);

        // 解析结果
        JSONObject resultJs = JSON.parseObject(result);
        if (0 != resultJs.getIntValue("errcode") || !"ok".equalsIgnoreCase(resultJs.getString("errmsg")))
            // 出错了。直接抛出,交给统一错误处理。
            throw new Exception(resultJs.getString("errmsg"));
        }

        // 拿到 js票据 和 过期时间。
        ticket = resultJs.getString("ticket");
        int expires_in = resultJs.getIntValue("expires_in"); // 这个时间单位是 秒

        // 保存到缓存。
        Util.setCache("ticket", ticket, expires_in);
    }

    return null;
}

代码里首先获取了基本参数。url 为了获取方便,前端将其url传入进来,注意如果你的页面是单页面的并且你的页面上的路由设定的是hash路径格式,那么你只需要将整个url中#号前面部分的内容传递给后端进行就可以了。

然后是从缓存里获取原来是否保存过js票据,由于此票据可以使用2小时,所以,这里增加一个判断,这样减少api请求次数,效率也更高。当然了,第一次是拿不到缓存数据的,这时候就通过微信接口去获取票据,获取成功后将其保存到缓存,并且设定过期时间,过期后将不能从缓存中获取到。代码中出现了2个工具方法帮我们完成了缓存的设定和获取,这两个方法如下:

public class Util {
    /* 为节省篇幅,其他代码已省略。 */

    // 从缓存中获取某key对应的值。
    public static String getCache(String key) {
        // 方法内没有实现,开发者应根据自己系统决定实现方式。
        return null;
    }
    // 将某key对应的值设置到缓存,并提供过期时间,在过期后将获取不到该值。
    public static void setCache(String key, String value, int expirein) {
        // 方法内没有实现,开发者应根据自己系统决定实现方式。
    }
}

这两个方法的具体实现,需要各位根据自己系统的缓存解决方案去处理,可能你使用了redis作为缓存,可能是直接使用内存缓存,也可能是数据库缓存。因此这两个方法需要自己去实现。

现在我们获取到了jsapi_ticket票据,可以进行数据签名了。

2、数据签名

这是摘自微信文档官方的文案介绍:

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

其中涉及了一些参数我们并未要求前端传入,我们可以自己生成,然后返回给前端使用就好了。所以在签名前我们先准备好需要的东西:

<!-- 准备数据 -->
jsapi_ticket:   上面已经获取到了
url:            上面已要求前端传入了
noncestr:       随机字符串  --> 随机生成
timestamp:      时间戳      --> 可使用当前时间

通过列表一展示出来,发现现在需要我们做的事情变得非常的简单了,继续完成接口代码, 为了节省篇幅,对于获取票据部分代码已隐藏:

@RequestMapping("/getWxJsCfg")
@RequestBody
public String getWxjsCfg(HttpServletRequest request) throws Exception {
    // 先获取必须的参数。
    // 通常传递当前页面的url。
    String url = request.getParameter("url");
    // 运行前端自己传递自己想要的哪些微信方法。多个使用逗号(英文逗号)隔开。
    String jsApiList = request.getParameter("jsApiList");

    // 获取 jsapi_ticket
    String ticket = Util.getCache("ticket"); // 先尝试从缓存获取。
    if (Util.isEmpty(ticket)) {
        // 缓存里没有获取到数据。则请求微信api获取。
        // 为了节省篇幅,此处代码已隐藏。
        /* ... */
    }

    // 生成随机字符串
    String noncestr = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
    // 拿到当前时间戳, 这个只需要到秒的时间戳即可。
    long timestamp = System.currentTimeMillis() / 1000;

    // 然后进行【按照字段名进行字典排序】
    String string1 = "jsapi_ticket=" + ticket    +
                     "&noncestr="    + noncestr  +
                     "&timestamp="   + timestamp +
                     "&url="         + url;

    // 最后进行sha1签名。
    String signature = Util.sha1(string1);

    // 然后返回给前端。
    JSONObject cfgForWx = new JSONObject();
    cfgForWx.put("appId", "自己微信公众号的appid");
    cfgForWx.put("timestamp", timestamp);
    cfgForWx.put("nonceStr", noncestr);
    cfgForWx.put("signature", signature);
    return cfgForWx.toJSONString();
}

上述代码中产生了随机字符串和时间戳。然后排序组建原数据,由于这个排序只需要根据字段名进行排序,所以直接按顺序写好即可,不用使用排序方法排序。最后进行签名,此处直接使用了Util中的快捷方法,要了解此方法,你可以到《【微信公众号开发】二、解析微信请求及响应消息》第四节进行浏览。

所有工作完成后,不要忘了将前端需要的必要参数返回给前端。返回数据格式可能各自系统都不一样,上方只是示列代码,自己的系统格式需要自己修改为相应格式。

五、前端调用接口获取配置

现在,后端已经为前端写好了获取配置的接口,那么前端要进行 wx.config(option) 前,调用接口,获取配置即可获取,假如你使用 Jquery 进行请求,则你可以参考下面的代码:

$.ajax({
    url: "后台接口域名/wechat/getWxJsCfg",
    type: 'POST',
    data: {
        url: window.location.href.split("#")[0]
    },
    dataType: 'json',
    success: function (response) {
        // 调起微信js的配置授权
        wx.config({
            appId: response.appId,
            timestamp: response.timestamp,
            nonceStr: response.nonceStr,
            signature: response.signature,
            // 需要使用的微信js方法
            jsApiList: ["chooseImage","uploadImage","hideMenuItems", /*...等*/]
        })
    },
    error: function (xmlHttpRequest, errorStr, exception) {
        // 处理出错
    }
});

进行了config后,就可以顺利的使用微信提供的各个方法了。不过还要注意 wx.config(option) 方法是一个异步方法,也就意味着,这行代码执行完成后,下一行你就调起微信js的其他方法,很有可能依然会出现错误。你必须要等该方法config成功之后再调起相应的方法。好在微信提供了一个配置成功回调,你只需要提供一个配置成功后要执行的方法,就可以在方法中实现配置成功后要立刻执行的逻辑:

wx.ready(function(){
    // 当config方法执行成功后,就会调用此方法,这里面的逻辑便可得到执行。
});

非常建议你在config方法调用前就先调用 ready 方法将要立刻执行的逻辑写好。比如下面示列一个完整的【页面一打开就隐藏[复制链接按钮]的操作】:

<!-- 此代码示列了如何一打开界面就隐藏[复制链接按钮] -->
<html>
<head>
<title>页面一打开就隐藏[复制链接按钮]</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
</head>
<body>
<h1>页面一打开就隐藏[复制链接按钮]</h1>
<script>
$(function () {
	// 首先定义好 config 配置成功执行的逻辑。
	wx.ready(function () {
		// 一旦 config 成功就隐藏按钮。
		// 此处代码在 config 成功后立即执行,所以写在这里准没错。
		wx.hideMenuItems({
			menuList: ["menuItem:copyUrl"],
			success: function (obj) {
				console.log("隐藏成功。");
			},
			fail: function (obj) {
				console.log("隐藏失败:", obj);
			}
		});
	});
	
	// 然后开始进行config。
	// 开始前,先请求接口获取参数。
	$.ajax({
		url: "后台接口域名/wechat/getWxJsCfg",
		type: 'POST',
		data: {
			url: window.location.href.split("#")[0]
		},
		dataType: 'json',
		success: function (response) {
			// 请求完成,调起微信js的配置授权
			wx.config({
				appId: response.appId,
				timestamp: response.timestamp,
				nonceStr: response.nonceStr,
				signature: response.signature,
				// 需要使用的微信js方法,此处演示只需要获取隐藏按钮api。
				jsApiList: ["hideMenuItems"]
			});
		},
		error: function (xmlHttpRequest, errorStr, exception) {
			// 处理请求出错
		}
});
});
</script>
</body>
</html>

六、总结

使用微信js的整体流程大致为:

获取js凭据-->使用凭据和其他参数加签-->前端进行config-->成功后开始使用对应方法

本文涉及一个网络请求工具类HttpUtil,如果你也是maven项目,你可以直接添加依赖来添加这个工具:

<dependency>
    <groupId>cn.microanswer</groupId>
    <artifactId>HttpUtil</artifactId>
    <version>1.0.1</version>
</dependency>
Full text complete, Reproduction please indicate the source. Help you? Not as good as one:
Comment(Comments need to be logged in. You are not logged in.)
You need to log in before you can comment.

Comments (1 Comments)