微信分享的那些坑

最近项目中有用到微信分享,记录下所遇到的坑
有兴趣的同学可以去研究下微信公众平台开发者文档

地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432

一、微信分享配置

首先在页面引用微信分享的js,注意js的版本,如果分享的链接是https开头的,建议js的版本在1.4.0以上 //res.wx.qq.com/open/js/jweixin-1.4.0.js
微信分享可以用初始化加载的方式或者ajax异步加载的方式

1.下面是页面加载完毕后即完成微信分享参数初始化的方法
初始化加载的意思就是,在页面加载完毕后,所有的参数已经完成赋值,可以直接进行微信分享,异步的化就是动态获取分享参数进行赋值(主要用于每次分享的文案有变化的情况)

(function(win, undefined) {

	 var $ = win.jQuery;
 	  if (typeof hideMenuItems != "undefined" && hideMenuItems) {
       wx.config({
           debug: false,
           appId: appId,
           timestamp: timestamp,
           nonceStr: noncestr,
           signature: signature,
           jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage', 'hideMenuItems']
       });
   } else {
       wx.config({
           debug: false,
           appId: appId,
           timestamp: timestamp,
           nonceStr: noncestr,
           signature: signature,
           jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage']
       });
   }


   wx.ready(function () {
       var shareData = {
           title: title,
           desc: desc,
           link: url,
           imgUrl: image,
           success: function (res) {
               $.ajax({
                   url: "/app/shareCallback?status=" + share,
                   type: "GET",
                   dataType: 'json',
                   success: function (d) {
                   }
               });
           },
           cancel: function (res) {

           },
           fail: function (res) {

           }
       };
       wx.onMenuShareTimeline(shareData);
       wx.onMenuShareAppMessage(shareData);
       if (typeof hideMenuItems != "undefined" && hideMenuItems) {
           var val = hideMenuItemsValue.split(",");
           wx.hideMenuItems({
               menuList: val // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
           });
       }
   });

   if (typeof WeixinJSBridge != "undefined") {
       var imgUrl = image;
       var lineLink = url;
       var descContent = desc;
       var shareTitle = title;
       var appid = appId;

       function shareFriend() {
           WeixinJSBridge.invoke('sendAppMessage', {
               "appid": appid,
               "img_url": imgUrl,
               "link": lineLink,
               "desc": descContent,
               "title": shareTitle
           }, function (res) {
               WeixinJSBridge.call('closeWindow');
               if (res.err_msg != 'send_app_msg:cancel' && res.err_msg != 'share_timeline:cancel') {
                   $.ajax({
                       url: "/app/shareCallback?status=" + share,
                       type: "GET",
                       dataType: 'json',
                       success: function (d) {
                           if (d.ret == 1) {
                            //分享朋友 回调
                               }
                           }
                       }
                   });
               }
           })
       }

       function shareTimeline() {
           WeixinJSBridge.invoke('shareTimeline', {
               "img_url": imgUrl,
               "link": lineLink,
               "desc": descContent,
               "title": shareTitle
           }, function (res) {
               WeixinJSBridge.call('closeWindow');
               if (res.err_msg != 'send_app_msg:cancel' && res.err_msg != 'share_timeline:cancel') {
                   $.ajax({
                       url: "/app/shareCallback?status=" + share,
                       type: "GET",
                       dataType: 'json',
                       success: function (d) {
                           if (d.ret == 1) {
                            	//分享 朋友圈 回调
                               }
                           }
                       }
                   });
               }
           });
       }

       // 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
       document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
           // 发送给好友
           WeixinJSBridge.on('menu:share:appmessage', function (argv) {
               shareFriend();
           });
           // 分享到朋友圈
           WeixinJSBridge.on('menu:share:timeline', function (argv) {
               shareTimeline();
           });
       }, false);
   }
})(window);

可以看到微信的配置中需要用到的几个参数,appId,timestamp,nonceStr,signature,jsApiList
这几个参数,需要在后台创建分享时传入页面。

2.后台获取参数代码如下:
//创建分享的参数
	public static void createShare(HttpServletRequest request, User user,String acivityName,String title,String desc,String img,String url){
		String query = request.getQueryString();
		String requestUrl = null;
		if(StringUtils.isEmpty(query)){
			requestUrl =  request.getRequestURL().toString();
		}else{
			requestUrl =  request.getRequestURL() + "?" + query;
		}

		Map<String,String> ret = WeiXinServiceUtil.sign(WeiXinServiceUtil.serviceTestAppId,WeiXinServiceUtil.serviceTestSecret,requestUrl);
		request.setAttribute("appId", ret.get("appId"));
		request.setAttribute("timestamp", ret.get("timestamp"));
		request.setAttribute("nonceStr", ret.get("nonceStr"));
		request.setAttribute("signature", ret.get("signature"));
		String activityRecordId = request.getParameter("activityRecordId");
		if(ValidateUtil.isNumber(activityRecordId)){
			request.setAttribute("share", acivityName+java.util.UUID.randomUUID().toString()+"&activityRecordId=" + activityRecordId + "&type=jxq&userId="+user.getUserId());
		}else{
			request.setAttribute("share", acivityName+java.util.UUID.randomUUID().toString());
		}

		request.setAttribute("title", title);
		request.setAttribute("desc", desc);
		request.setAttribute("image", img);
		int userId = 0;
		if(user != null){
			userId = user.getUserId();
			url += "&ref=" + IDEncryptor.getInstance().encryptWithoutException(userId);
		}

		request.setAttribute("appurl", url);
		try{
			request.setAttribute("apptitle", java.net.URLEncoder.encode((String)request.getAttribute("title"), "UTF-8"));
			request.setAttribute("appdesc", java.net.URLEncoder.encode((String)request.getAttribute("desc"), "UTF-8"));
			request.setAttribute("url", url);
			url = java.net.URLEncoder.encode(url, "utf-8");
			Boolean needWeiChatInfo = (Boolean)request.getAttribute("needWeiChatInfo");
			String platSource = request.getAttribute("platSource").toString();
			if(needWeiChatInfo != null && needWeiChatInfo == true && !platSource.equals("3")){
				//url = url.replace("&","%26");
				String tq = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeiXinServiceUtil.serviceTestAppId+ "&redirect_uri=" + url +"&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
				request.setAttribute("url", tq);
				request.setAttribute("appurl", tq);
			}
		}catch(Exception exp){
			logger.error(exp.getMessage(),exp);
		}
	}

//微信验签方法
public synchronized static Map<String, String> sign(String appId,String secret,String url) {
    Map<String, String> ret = new HashMap<String, String>();
    String nonce_str = create_nonce_str();
    String timestamp = create_timestamp();
    String string1;
    String signature = "";

    JedisUtil jedisUtil = JedisUtil.getInstance();
    String shareKey = jedisUtil.getJedisString(RedisConstant.REDIS_WX_SHARE_TOKEN_KEY);
    //if(last_access  == 0 || (System.currentTimeMillis() - last_access) > 2*3600*1000L){
    if(StringUtil.isEmpty(shareKey)){
    	jsapi_ticket = httpToken(appId,secret);
    	if(StringUtils.isEmpty(jsapi_ticket)){
    		jsapi_ticket = httpToken(appId,secret);
    		if(StringUtils.isEmpty(jsapi_ticket)){
    			return ret;
    		}
    	}
    	jedisUtil.setStringAndTime(RedisConstant.REDIS_WX_SHARE_TOKEN_KEY, jsapi_ticket, RedisConstant.REDIS_WX_SHARE_TOKEN_KEY_TIME);
    }else{
    	jsapi_ticket = shareKey;
    }

	boolean notHTTPS = url.startsWith("http://" + Config.MOBILE_DOMAIN);
	if(notHTTPS && !Config.DEBUG) {
		url = url.replace("http", "https");
	}
    //注意这里参数名必须全部小写,且必须有序
    string1 = "jsapi_ticket=" + jsapi_ticket +
              "&noncestr=" + nonce_str +
              "&timestamp=" + timestamp +
              "&url=" + url;

    try
    {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(string1.getBytes("UTF-8"));
        signature = byteToHex(crypt.digest());
    }
    catch (NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch (UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }

    ret.put("url", url);
    ret.put("jsapi_ticket", jsapi_ticket);
    ret.put("nonceStr", nonce_str);
    ret.put("timestamp", timestamp);
    ret.put("signature", signature);
    ret.put("appId", appId);
    return ret;
}
3.异步方法创建动态分享参数 代码如下
	/**
	 * ajax请求获取分享参数
	 * @param request
	 * @param user
	 * @param acivityName
	 * @param title
	 * @param desc
	 * @param img
	 * @param url
	 * @param retMap
	 */
	public static void ajaxCreateShare(HttpServletRequest request, User user,String acivityName,String title,String desc,String img,String url, Map<String, Object> retMap){
		String query = request.getParameter("htmlUrl");
		String requestUrl = null;
		if(StringUtil.isNotEmpty(query)){
			requestUrl = query;
		}else{
			query = request.getQueryString();
	  	    if(StringUtils.isEmpty(query)){
	  	    	requestUrl =  request.getRequestURL().toString();
	  	    }else{
	  	    	requestUrl =  request.getRequestURL() + "?" + query;
	  	    }
		}


  	    Map<String,String> ret = WeiXinServiceUtil.sign(WeiXinServiceUtil.serviceTestAppId,WeiXinServiceUtil.serviceTestSecret,requestUrl);
  	    retMap.put("appId", ret.get("appId"));
  	    retMap.put("timestamp", ret.get("timestamp"));
  	    retMap.put("nonceStr", ret.get("nonceStr"));
  	    retMap.put("signature", ret.get("signature"));
  	    retMap.put("share", acivityName+java.util.UUID.randomUUID().toString());
  	    
  	    retMap.put("title", title);
  	    retMap.put("desc", desc);
  	    retMap.put("image", img);
	    retMap.put("appurl", url);
		try{
			retMap.put("apptitle", java.net.URLEncoder.encode((String)retMap.get("title"), "UTF-8"));
			retMap.put("appdesc", java.net.URLEncoder.encode((String)retMap.get("desc"), "UTF-8"));
			retMap.put("url", url);
		}catch(Exception exp){
			logger.error(exp.getMessage(),exp);
		}
	}

异步获取分享参数的时候,需要注意传入当前要分享的页面的地址,微信验签时,验签的地址要与当前页面的地址保持一直,否则会导致微信校验失败,也就是分享出去的参数有误分享失败(坑)。

二、借助微信开发者工具

微信开发者工具,可以帮助我们模拟生产环境校验参数是否可以通过,当然你要准备好appId和可用的域名,便于微信校验
下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

以上图片是一个分享正确的情况下的示例
上图是一个分享检验通过的示例

三、微信分享公众号授权无法完成分享以及解决方案
	微信无感授权可以获取用户的一个唯一标识openid ,可以对微信用户和平台用户进行关联。以我们的项目为例子,可以通过openid判断用户是否有进行过公众号关注,是否绑定平台等信息。
	在我们分享的时候,如果需要进行分享并判断微信用户是否有相关操作的时候,
	"https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid+ "&redirect_uri=" + url +"&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect" 
	前面是无感授权的链接,redirect_uri 是分享后要跳转的链接
	就需要向微信发送请求获取该openid,但是神奇的是微信竟然不给自己的链接进行校验通过,也就是说分享出去的链接必须是本项目的链接才可以。
	要想解决这个问题,可以通过项目中转链接实现跳转,也可以通过按钮跳转来实现。
	也就是说通过一个中间请求去重定向到我们带授权的请求就可以了。(如果有更好的方法,或者微信在后续的版本中解决了这个问题,请联系我,谢谢!)

本人水平有限,如有不当之处欢迎各位批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值