微信jssdk h5分享

4 篇文章 0 订阅
1 篇文章 0 订阅

使用微信jssdk进行h5分享

记录一下自己在开发jssdk过程和遇到的坑,最大的坑我觉得是:后台返回签名和验证工具签名一致,任然报错invalid signature,解决方法看文末。

一、首先,要严格按照微信文档步骤执行前面几个步骤,不然后面你会发现很多莫名其妙的坑。这里主要是4个步骤:

JSSDK使用步骤

步骤一:绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

步骤二:引入JS文件
在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.4.0.js

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持https)。

备注:支持使用 AMD/CMD 标准模块加载方法加载

在这里介绍一种vue文件引入js文件的方法 - - 混入 (mixins)

/* loadExternalAssetMixin.js */

const loadExternalAssetMixin = {
  methods:{
    loadScript(src, callback) {
      if (!(typeof callback === 'function')) {
        callback = function() {}
      }
      var check = document.querySelectorAll(`script[src="${src}"]`)
      if (check.length > 0) {
        check[0].addEventListener('load', function() {
          callback()
        })
        callback()
        return
      }
      var script = document.createElement('script')
      var head = document.getElementsByTagName('head')[0]
      script.type = 'text/javascript'
      script.charset = 'UTF-8'
      script.src = src
      if (script.addEventListener) {
        script.addEventListener('load', function() {
          callback()
        }, false)
      } else if (script.attachEvent) {
        script.attachEvent('onreadystatechange', function() {
          var target = window.event.srcElement
          if (target.readyState === 'loaded') {
            callback()
          }
        })
      }
      head.appendChild(script)
    }
  }
}
export default loadExternalAssetMixin

引入方式:

/* xxx.vue */
<script>
import loadExternalAssetMixin from '../util/loadExternalAssetMixin'
export default {
	mixins: [ loadExternalAssetMixin]mounted () {
		this.loadScript('http://res.wx.qq.com/open/js/jweixin-1.4.0.js', () => {
			// 回调
		})
	}
}
</script>

步骤三:通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

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

签名算法见文末的附录1,所有JS接口列表见文末的附录2

附录1-JS-SDK使用权限签名算法

jsapi_ticket

生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token)

2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

成功返回如下JSON:

{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

签名算法

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

即signature=sha1(string1)。 示例:

noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value

步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:

jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature:

0f9de62fce790f9a083d5c99e95740ceb90c27ed

注意事项

1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。

2.签名用的url必须是调用JS接口页面的完整URL。

3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。

如出现invalid signature 等错误详见附录5常见错误及解决办法。


签名方法需要放在后台,不放在vue前端,而是前端向后台请求signature

签名方法:
/* signature.js */
const config = require('../config')
const crypto = require('crypto')
const API = require('../wechat/api')
const api = new API(config.wechat.appid, config.wechat.appsecret)

// 生成随机字符串
let createNonceStr = function () {
  return Math.random().toString(36).substr(2, 15);
}
// 生成时间戳
let createTimestamp = function () {
  return parseInt(new Date().getTime() / 1000) + '';
}
//对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1 = value1 & key2=value2…)拼接成字符串string
let raw = function (args) {
    let keys = Object.keys(args)
    keys = keys.sort()
    let string = ''
    keys.forEach(k => {
        string += '&' + k + '=' + args[k]
    })
    string = string.substr(1)
    return string
}
//生成签名
class Signature {
  static async sign (ctx) {
    const { jsapi_ticket } = await api.ensureTicket() //获取到的jsapi_ticket, 具体可看https://github.com/Laumlin/wechat-public
    let ret = {
      jsapi_ticket: jsapi_ticket,
      noncestr: createNonceStr(),
      timestamp: createTimestamp(),
      url: ctx.request.body.url
    }
    const string = raw(ret)
    let hash = crypto.createHash('sha1')
    hash.update(string)
    ret.signature = hash.digest('hex')
    ctx.response.body = ret
  }
}

module.exports = Signature

步骤四:通过ready接口处理成功验证

wx.ready(function(){
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
<script>
export default {
  mounted() {
    this.loadScript('http://res.wx.qq.com/open/js/jweixin-1.4.0.js', () => {
      console.log('import jssdk success')

      let url = `${NODE_URL}${this.$store.state.redirectURL}` // 获取当前页面的url

      this.$axios({
        method: 'post',
        url:`${MP_BASEURL}/getSignature`,
        data: {
          'url': url
        }
      }).then(res => {
        wx.config({
          debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
          appId: this.$store.state.wechatAppId, // 必填,公众号的唯一标识
          timestamp: res.data.timestamp, // 必填,生成签名的时间戳
          nonceStr: res.data.noncestr, // 必填,生成签名的随机串
          signature: res.data.signature,// 必填,签名
          jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData','onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表
        })
        wx.ready(()=>{
          this.setWechatConfig(this.config)
        })
      })
    })
  },
  computed: {
    config () {
      return {
          title: 'share_title',
          desc: 'share_description',
          img:'',
          img_title:'share_img_title',
          link: `${NODE_URL}${this.$route.fullPath}`
        }
    },
  },
  methods: {
    onComplete (way) {
      return () => {
        // 成功回调
      }
    },
    setWechatConfig (newVal) {
      // 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
      wx.onMenuShareAppMessage({
        title: newVal.title, // 分享标题
        desc: newVal.desc, // 分享描述
        link: newVal.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
        imgUrl: newVal.img, // 分享图标
        type: 'link',
        dataUrl: '',
        success: this.onComplete('wechatFriend')
      })
      // 自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容
      wx.onMenuShareTimeline({
        title: newVal.title, // 分享标题
        link: newVal.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
        imgUrl: newVal.img, // 分享图标
        success: this.onComplete('wechatTimeline')
      })
    },
  }
}
 </script>
填坑:

url必须是当前网址的url,不包含‘#’后面部分,不能是本地地址http://localhost:8080/之类的,而且url的domain必须在微信安全域名之中。这也是我之前很头痛的一件事,后台返回的签名和微信签名检工具一样,任然报错,一直报invalid signature的错误,找到半天,签名和验证工具签名一致,只能说明你签名时的url和wx校验时的url不一致,原来用local域的url生成的签名wx.config检验不通过,最后在线上环境,url的域名是可以直接访问到的,签名终于通过了。 还有一点需要注意的是url中如果有中文,只需要对中文作encodeURIComponent()处理,’/'等符号不用。
总结:微信公众号和jssdk的开发都需要在线上环境,或者你在本地设置域名击穿等设置,让外网能直接访问到你本地,最后吐槽一下:微信对开发者太不友好了~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值