JS-SDK的使用(微信多次分享)

JS-SDK的使用(微信多次分享)
需求描述:公司通过APP产品分享出去的需求和简历是做了一个H5页面作为分享的链接,通过APP分享出去自然是没问题,也是第一次分享,之后通过微信打开H5页面后想再次分享出去时候就变成了一个链接了,而不是自己定制的卡片模式,初次分享后如下:
但是打开以后的H5页面再分享出去就变成这个样子了:

也就是说需要在H5页面做微信分享的相关工作,JS-SDK上场了,首先看看JS-SDK的官方说明文档: https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
按照文档说明一步一步的做下去就可以出结果了,在这里详细说一下每一步如何操作以及如何避坑,重点在于如何避坑。
  1. 绑定域名
    1. 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
    2. 上面是说明文档的原话,这里我介绍一下在开发阶段如何测试。
      1. 首先你得有一个微信公众平台测试账号,总不能用公司的公众账号进行开发测试吧,当然你有自己的公众号是最好的,没有的话就快速的申请一个接口测试号吧
      2. 访问微信公众平台测试版系统:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
      1. 主要是获取到测试号的appID和appsecret以及绑定J接口的安全域名:
      1. 绑定域名这块其实有蛮多坑的,就将我遇到的坑给大家说一下,希望遇到的人能够很好的解决:
        1. 域名不能加http://或者https://前缀,直接test.wxwx.com好了,否则回报invalid domain url无效的域
        2. 可以加端口号比如:test.wxwx.com:8888
        3. 也可以是一个ip地址比如:123.45.24.37
        4. 如何在本地进行测试?请下载一个代理服务器工具Fiddler:https://www.telerik.com/download/fiddler然后选择选项Tools->HOSTS
        1. 前面是你自己机器的Ip地址,后面是你自己定义的一个地址,然后在公众号里面添加wxwuwei.ceshiweixin.com:8888,Fiddler的端口是8888,然后保证你的机器和你的手机在同一个局域网下,进入手机设置你的网络连接如下图所示:
        1. 这个手机设置的ip一定要和你的PC的ip一样,这样前期环境准备工作就完成了,就可以开始编码部分了~
  1. 页面引入JS文件http://res.wx.qq.com/open/js/jweixin-1.0.0.js,这个就不多说了
  2. 通过config接口注入配置信息,微信需要去验证的, 如果验证通过了会执行wx.ready方法,这个JS-SDK文档有详细说明,这里主要说一下后台如何生成config中需要的配置信息:
    1  wx.config({
    2      debug:  true //  开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    3      appId: '',  //  必填,公众号的唯一标识
    4      timestamp: ,  //  必填,生成签名的时间戳
    5      nonceStr: '',  //  必填,生成签名的随机串
    6      signature: '', //  必填,签名,见附录1
    7      jsApiList: []  //  必填,需要使用的JS接口列表,所有JS接口列表见附录2
    8  });
  1. appId我们已经获取到了,timestamp时间戳是到秒的,千万别到毫秒,可以new Date().getTime()/1000获取一个就可以了,nonceStr是咱们自己定义的一个串,可以是随机串也可以是一个固定的字符串,signature是根据当前的jsapi_ticket、nonceStr、timestamp、url(当前网页的url,不包含#及其后面部分)四个字段拼串(需要按照ASCII码从小到大排序进行拼串abcdefg的顺序)进行SHA1加密生成的,这些都是需要在服务器端实现。
  2. access_token的获取https://mp.weixin.qq.com/wiki/15/54ce45d8d30b6bf6758f68d2e95bc627.html
    1. 需要缓存,因为这个接口的调用是有次数限制的,可以放在redis中
  3. 卡券 api_ticket的获取:根据获取到的access_token来获取api_ticket
    1. 获取url:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card
    2. 需要缓存,也是有次数限制的,可以放在redis中
  4. 常见错误及解决方法:见说明文档的附录5-常见错误及解决方法,其中的红字部分是你需要注意的坑,也是你解决微信多次分享的关键之处:确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败
下面根据上面描述的步骤贴出部分代码(Java版的),仅供参考!
首先写一个WeixinUtils.java类:
  1  package  com.freekeer.c.util;
  2 
  3  import  java.security.MessageDigest;
  4  import  java.util.Formatter;
  5  import  java.util.HashMap;
  6  import  java.util.Map;
  7  import  java.util.Properties;
  8 
  9  import  org.apache.commons.lang3.StringUtils;
 10 
 11  import  com.alibaba.fastjson.JSONObject;
 12 
 13  public   class  WeiXinUtils {
 14 
 15       //  微信appId
 16       private   static  String APPID;
 17       //  微信公众号唯一密钥
 18       private   static  String APPSECRET;
 19       //  获取acc_token的接口
 20       private   static  String ACC_TOKEN_URL;
 21       //  获取jsapi_ticket url
 22       private   static  String JSAPI_TICKET_URL;
 23       //  生成签名的随机串
 24       private   static  String NONCE_STR;
 25 
 26       static  {
 27          Properties prop  =  AppPropTools.getProperties( " /weixin.properties " );
 28          APPID  =  prop.getProperty( " APPID " );
 29          APPSECRET  =  prop.getProperty( " APPSECRET " );
 30          ACC_TOKEN_URL  =  prop.getProperty( " ACC_TOKEN_URL " +   " &appid= "   +  APPID
 31                   +   " &secret= "   +  APPSECRET;
 32          JSAPI_TICKET_URL  =  prop.getProperty( " JSAPI_TICKET_URL " );
 33          NONCE_STR  =  prop.getProperty( " NONCE_STR " );
 34      }
 35 
 36       //  私有构造方法
 37       private  WeiXinUtils() {
 38 
 39      }
 40 
 41       /**
 42       * 获取微信acc_token
 43       * 
 44       *  @return
 45       *  @throws  Exception
 46        */
 47       public   static  String getAccToken()  throws  Exception {
 48           //  先从redis取,取不到再从微信里面取
 49          String weixin_acc_token  =  RedisHelper.getStringValue(
 50                   " weixin_acc_token " 2 );
 51           if  (StringUtils.isEmpty(weixin_acc_token)) {
 52              String resultStr  =  HttpURLConnectionUtil
 53                      .getWebHTMLCode(ACC_TOKEN_URL);
 54              JSONObject resultObj  =  JSONObject.parseObject(resultStr);
 55              String accToken  =  resultObj.getString( " access_token " );
 56               int  expiresIn  =  resultObj.getIntValue( " expires_in " );
 57               //  写进redis
 58              RedisHelper.setStringValue( " weixin_acc_token " , accToken, expiresIn,
 59                       2 );
 60               return  accToken;
 61          }
 62           return  weixin_acc_token;
 63 
 64      }
 65 
 66       /**
 67       * 获取微信票据
 68       * 
 69       *  @return
 70       *  @throws  Exception
 71        */
 72       public   static  String getTicket()  throws  Exception {
 73           //  先从redis中取ticket,没有再从这里取
 74          String weixin_js_api_tiket  =  RedisHelper.getStringValue(
 75                   " weixin_js_api_tiket " 2 );
 76           if  (StringUtils.isEmpty(weixin_js_api_tiket)) {
 77 
 78              String accToken  =  getAccToken();
 79              String resultStr  =  HttpURLConnectionUtil
 80                      .getWebHTMLCode(JSAPI_TICKET_URL  +  accToken);
 81              JSONObject resultObj  =  JSONObject.parseObject(resultStr);
 82               if  (resultObj.getIntValue( " errcode " ==   0 ) {
 83                  String ticket  =  resultObj.getString( " ticket " );
 84                   int  expires_in  =  resultObj.getIntValue( " expires_in " );
 85                   //  写入redis
 86                  RedisHelper.setStringValue( " weixin_js_api_tiket " , ticket,
 87                          expires_in,  2 );
 88                   return  ticket;
 89              }
 90               return   null ;
 91          }
 92           return  weixin_js_api_tiket;
 93      }
 94 
 95       /**
 96       * 获取签名
 97       * 
 98       *  @param  timeStamp
 99       *  @param  requestUrl
100       *  @return
101       *  @throws  Exception
102        */
103       public   static  String getSignature(Long timeStamp, String requestUrl)
104               throws  Exception {
105          String ticket  =  getTicket();
106          StringBuffer allStr  =   new  StringBuffer( " jsapi_ticket= " );
107          allStr.append(ticket).append( " &noncestr= " ).append(NONCE_STR)
108                  .append( " &timestamp= " ).append(timeStamp).append( " &url= " )
109                  .append(requestUrl);
110          MessageDigest crypt  =  MessageDigest.getInstance( " SHA-1 " );
111          crypt.reset();
112          crypt.update(allStr.toString().getBytes( " UTF-8 " ));
113          String signature  =  byteToHex(crypt.digest());
114           return  signature;
115      }
116 
117       /**
118       * SHA1加密
119       * 
120       *  @param  hash
121       *  @return
122        */
123       private   static  String byteToHex( final   byte [] hash) {
124          Formatter formatter  =   new  Formatter();
125           for  ( byte  b : hash) {
126              formatter.format( " %02x " , b);
127          }
128          String result  =  formatter.toString();
129          formatter.close();
130           return  result;
131      }
132 
133       /**
134       * 获取微信JS页面Config所需参数
135       * 
136       *  @param  timeStamp
137       *  @param  requestUrl
138       *  @return
139       *  @throws  Exception
140        */
141       public   static  Map < String, Object >  getConfig( long  timeStamp,
142              String requestUrl)  throws  Exception {
143          Map < String, Object >  map  =   new  HashMap < String, Object > ();
144          String signature  =  getSignature(timeStamp, requestUrl);
145          map.put( " signature " , signature);
146          map.put( " nonceStr " , NONCE_STR);
147          map.put( " timestamp " , timeStamp);
148          map.put( " appId " , APPID);
149           return  map;
150      }
151 
152  }
153

再写一个接口类返回config中的参数:

 1  package  com.freekeer.c.controller;
 2 
 3  import  java.util.Date;
 4  import  java.util.Map;
 5 
 6  import  javax.servlet.http.HttpServletRequest;
 7  import  javax.servlet.http.HttpServletResponse;
 8 
 9  import  org.slf4j.Logger;
10  import  org.slf4j.LoggerFactory;
11  import  org.springframework.web.bind.annotation.RequestMapping;
12  import  org.springframework.web.bind.annotation.RequestMethod;
13  import  org.springframework.web.bind.annotation.RequestParam;
14  import  org.springframework.web.bind.annotation.RestController;
15 
16  import  com.freekeer.c.util.WeiXinUtils;
17 
18  /**
19   * 热搜词控制层
20   * 
21   *  @author  WuWei
22    */
23  @RestController
24  public   class  WeixinController  extends  BaseController {
25 
26      @SuppressWarnings( " unused " )
27       private   static  Logger log  =  LoggerFactory.getLogger(WeixinController. class );
28 
29      @RequestMapping(value  =   " /wx-config " , method  =  { RequestMethod.GET })
30       public  Map < String, Object >  getConfig(HttpServletRequest request,
31              HttpServletResponse response, @RequestParam(value = " url " , required = true ) String url)  throws  Exception {
32           long  timeStamp  =   new  Date().getTime() / 1000 ;
33          Map < String, Object >  result  =  WeiXinUtils.getConfig(timeStamp, url);
34           return  result;
35      }
36      
37  }
38

JS端通过ajax调用

 1  function  weixinShareZp(demandData) {
 2       var  title  =  demandData.profession;
 3       var  desc  =  demandData.projectName + " ,在 " + demandData.workCityName + " 招聘 " + title + demandData.requireStaffCount + " " ;
 4       var  url  =   " ../wx-config?url= " + encodeURIComponent(window.location.href);
 5       var  logoUrl  =   " http://xxx-resource-public.oss-cn-beijing.aliyuncs.com/share_img/logo.png " ;
 6      $.get(url,[], function (data) {
 7          wx.config({
 8              debug: true ,
 9              appId:data.appId,
10              timestamp:data.timestamp,
11              nonceStr:data.nonceStr,
12              signature:data.signature,
13              jsApiList: [
14                  'onMenuShareTimeline', 
15                  'onMenuShareAppMessage', 
16                  'onMenuShareQQ',
17                  'onMenuShareWeibo',
18                  'onMenuShareQZone'
19              ]
20          });
21          wx.ready( function (){ 
22               //  获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 
23              wx.onMenuShareTimeline({ 
24                  imgUrl:logoUrl,
25                    link:window.location.href,
26                    desc:desc,
27                    title:title,
28                    type: " link "
29              }); 
30               //  获取“分享给朋友”按钮点击状态及自定义分享内容接口 
31              wx.onMenuShareAppMessage({ 
32                  imgUrl: logoUrl,
33                    link: window.location.href,
34                    desc: desc,
35                    title: title,
36                    type:  " link "
37              });
38              wx.onMenuShareQQ({
39                  title: title,
40                  desc: desc,
41                  link: window.location.href,
42                  imgUrl: logoUrl
43              });
44              wx.onMenuShareWeibo({
45                  title: title,
46                  desc: desc,
47                  link: window.location.href,
48                  imgUrl: logoUrl,
49              });
50              wx.onMenuShareQZone({
51                  title: title,
52                  desc: desc,
53                  link: window.location.href,
54                  imgUrl: logoUrl,
55              });
56          });
57 
58      });
59  }
开始通过微信分享进行测试吧!

你可能感兴趣的:(JS-SDK的使用(微信多次分享))