这几天做了微信分享功能的修改,通过微信 jssdk 可以修改微信右上角分享到朋友圈、分享给朋友、分享到QQ这些界面的 Title、Description和 Image,用来让分享更有质量。普通情况下如果你没有使用 jssdk 去配置你分享的 Title 等信息,微信会将分享出来的 Title 设置为你网页的 Title 内容,将 Description 设置为网站的 Url,而图片则取文章中第一幅图片,如果文章中没有图片,那么分享出去的图片就是空白的。

在 Meteor 环境下使用微信的 jssdk 让我遇到了一个非常头大的问题,在微信 wx.config 初始化函数中配置 signature 的时候,一直提示 config:invalid signature。如下所示: 2.pic_hd 几番周折,网上的资料都说你前台的 Url 和传递到后台计算 signature 的 Url 不一样,而我反复检查代码写的的确没有任何问题,前台 window.location.href 取到的 Url 和传递到后台计算 signature 的 Url 一模一样,无奈在公司没有解决这个问题。 到家里点了饭准备继续攻坚时,无意打开了 Windows 下微信的客户端,在公共号那个提示 config:invalid signature 出错页面的位置,点了一下使 “使用默认浏览器打开” 的按钮: 1.pic 赫然发现,浏览器中的 Url 跟我实际分享页面的地址完全不一样。这是闹鬼了吗?本着以科学的角度解决问题的态度,我仔细想了想原因,最后确认,如果是根据某篇文章 ID 或某用户 ID 动态变换的 Url 中,这个问题就存在,而首页、about等固定 Url 的页面,是没有这种问题的。这个问题就出现在了 Iron.Router 所分配的路由上。

有问题的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.route('activityShow', {
template: 'activityShow',
path: '/activities/:_id',
waitOn: function () {
Meteor.subscribe('images');
return Meteor.subscribe('activityComposite', this.params._id);
},
data: function () {
return {
enrollments: Enrollments.find(),
activity: Activities.findOne(this.params._id),
comments: Comment.collection.find(),
}
},
});

无问题的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.route('activitiesIndex', {
template: 'activitiesIndex',
path: '/activities',
waitOn: function () {
Meteor.subscribe('images');
Meteor.subscribe('enrollments', this.params._id);
return Meteor.subscribe('activitiesComposite');
},
data: function () {
return {
activities: Activities.find({}, {sort: {createdAt: -1}}),
enrollments: Enrollments.find(),
}
}
});

我们发现,会报错的页面的 Route,都是根据某些 ID 动态变换的,实际页面在加载过程中,layout 是不变的,只是更新了页面中的某个块,而对页面 Url 的修改是在微信客户端获取完当前 Url 之后再执行的操作,导致微信获取的 Url 还是页面跳转前的 Url(所以我们使用默认浏览器打开的时候它的 Url 与我们实际页面的不一样),这就造成我们实际传递给后台计算 signature 的 Url 和微信客户端自己获取的 Url 是不一样的(虽然我们看到 window.location.href 是正确的,但这是假象)。微信自己获取的 Url 是该页面的前一个页面的 Url,而如果我们在会报错的页面原地刷新,你会发现 wx.config 不再报错了,这是因为微信此时获取的 Url 和我们当前刷新页面的 Url 是一致的。 接下来就是解决这个问题了,我们该如何在程序中判断这种情况的出现呢?给大家分享一个包。包名叫 Iron.Location,GitHub 地址:https://github.com/iron-meteor/iron-location,这个包中有一个属性是 host,如果是上文中提到的根据文章 ID 或者用户 ID 动态变换的页面,首次进入时,该值为空,如果原地刷新,该值是一个正常的该页面的 Url。我们可以根据这个值来进行判断,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var url = "";
var current = Iron.Location.get();

if (current.host == "") {
// route 过来的地址,微信只能获取到 /activities 截止,后面的取不到了,我们设定为微信自己获取的地址
url = "http://x-lab.maodou.io/activities";
} else {
// 刷新页面或者新建文章后跳转的页面,微信获取的是完整地址
url = window.location.href;
}

// 根据不同情况传递不同的地址获取 signature
Meteor.call("signature", url, function(error, result) {
// 执行 wx.config 初始化
});

通过以上方法,我们可以成功的判断是从某个页面跳转进来的,还是原地刷新等情况,根据不同情况给后台传递不同的 Url 来计算 signature,以初始化 wx.config。至此问题算是解决,但不算完美解决。因为对浏览器和 JavaScript 不是非常了解。我无法解释更多信息,只能给大家先提出解决办法。希望后面使用 Meteor 开发微信公共号的人可以避免这个问题。并从中找出更多可靠的解决方案。