微信二次分享解决图标文案失效方案

转自:https://www.cnblogs.com/backtozero/p/7064247.html

前言

刚进入一家新公司,接到的第一个任务就是需要需要自定义微信分享的效果(自定义缩略图,标题,摘要),一开始真是一脸懵逼,在网上搜索了半天之后大概有了方案。值得注意的是一开始搜索到的解决方案全是调用微信的自带的JS-SDK,然而腾讯是不会让广大吃瓜群众这么轻而易举的调用他们的东西的。微信开发团队已经把调用的权限收回,现在无法直接在页面直接调用JS-SDK了。话不多说,直接上干货。

预期效果

原始的分享效果:

微信二次分享解决图标文案失效方案_第1张图片

 

使用微信JS-SDK的分享效果:

微信二次分享解决图标文案失效方案_第2张图片

可以看出缩略图,标题,摘要样式良好,给用户的体验很好。

准备工作

微信官方开发者文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

现在的思路已经很明确了,就是通过调用微信的JS-SDK实现自定义分享效果。但是这个调用过程比较繁琐,需要提前准备如下东西:

(1)微信服务号一个,并且已经通过了实名认证;

   没有实名认证的话,一些接口没有调用权限。

(2)一个ICP备案的域名;

这个域名需要设置为微信公众号后台的JS接口安全域名,否则微信仍然不允许调用它的接口。

这时大家应该就犯难了,这样的话岂不是不能在本地测试,只能部署到生产环境才能测试?不用着急,解决方案告诉大家:花生壳的内网穿透服务(收费,20元以内)

花生壳官网:http://hsk.oray.com/price/#personal

选择个人免费版就可以了,虽然说是免费版,但是其实注册过程中还是要收几块钱的,因为我自己买了域名和流量所以花的钱更多一些,但也在20元以内。不建议大家购买流量,送的流量可以用很久了。

当准备好上面提到的就可以开始敲代码了。

(3)安装微信开发者工具,用于本地调试。

下载地址:https://mp.weixin.qq.com/debug/cgi-bin/webdebugger/download?from=mpwiki&os=x64

官方使用教程:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140

具体步骤

(1)查看AppId,AppSecret以及绑定域名

进入微信后台,找到下面的菜单

微信二次分享解决图标文案失效方案_第3张图片

获取AppID和AppSecret

微信二次分享解决图标文案失效方案_第4张图片

设置JS接口安全域名

微信二次分享解决图标文案失效方案_第5张图片

 微信二次分享解决图标文案失效方案_第6张图片

 微信二次分享解决图标文案失效方案_第7张图片

注意第三步,如果微信服务器不能在我们的服务器上访问到这个txt文件,域名是无法设置成功的,这里先告诉大家在哪里设置,想要成功设置域名还需要使用花生壳的服务,让微信服务器访问我们本地工程中的的txt文件才行。

hkh3321313.vicp.io是在花生壳上购买的域名,免费送的域名是在太难记了,完全不能忍。

 

(2)引入JS文件

这里需要注意是http还是https,如果生产环境是https,务必前缀是https,都则会出现mix content这样的错误,导致引入失败。

 

(3)通过AppId和AppSecret请求accessToken,然后通过accessToken获取jsapi_ticket,生成config接口所需参数

因为获取这两个参数的次数是有限制的(accessToke 每日2000次,jsapi_ticket 每日100000次),有效期是7200秒,每两小时请求一次就行啦,把获取的accessToke和jsapi_ticket保存在后台,所以accessToken和jsapi_ticket这两个参数的获取是通过ajax方式请求后台,而不是实时去获取的。

config几个参数需要详细说明一下:

  1. timestamp  生成签名的时间戳  create_nonce_str()
  2. nonceStr  随机生成的字符串 create_timestamp()
  3. signature  按照微信文档签名算法生成的签名 makeWXTicket()

附上signature算法的官方说明:

https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.15697429783636763#buzhou3

在附录1中可以找到详细说明。

此外,官方提供了一个签名算法的校验工具:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

下面只附上了主要的方法:

复制代码
//获取accessToken
private JSONObject getAccessToken(){
    //String accessTokenUrl= https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    String requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);
    log.info("getAccessToken.requestUrl====>"+requestUrl);
    JSONObject result = HttpUtil.doGet(requestUrl);
    return result ;
}

//获取ticket
private JSONObject getJsApiTicket(){
//String apiTicketUrl= https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
String requestUrl = apiTicketUrl.replace(“ACCESS_TOKEN”, accessToken);
log.info(
“getJsApiTicket.requestUrl====>”+requestUrl);
JSONObject result
= HttpUtil.doGet(requestUrl);
return result;
}

//生成微信权限验证的参数
public Map makeWXTicket(String jsApiTicket, String url) {
Map
ret = new HashMap();
String nonceStr
= createNonceStr();
String timestamp
= createTimestamp();
String string1;
String signature
= “”;

//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsApiTicket +
        "&noncestr=" + nonceStr +
        "&timestamp=" + timestamp +
        "&url=" + url;
log.info("String1=====>"+string1);
try
{
    MessageDigest crypt = MessageDigest.getInstance("SHA-1");
    crypt.reset();
    crypt.update(string1.getBytes("UTF-8"));
    signature = byteToHex(crypt.digest());
    log.info("signature=====>"+signature);
}
catch (NoSuchAlgorithmException e)
{
    log.error("WeChatController.makeWXTicket=====Start");
    log.error(e.getMessage(),e);
    log.error("WeChatController.makeWXTicket=====End");
}
catch (UnsupportedEncodingException e)
{
    log.error("WeChatController.makeWXTicket=====Start");
    log.error(e.getMessage(),e);
    log.error("WeChatController.makeWXTicket=====End");
}

ret.put("url", url);
ret.put("jsapi_ticket", jsApiTicket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
ret.put("appid", appId);

return ret;

}
//字节数组转换为十六进制字符串
private static String byteToHex(final byte[] hash) {
Formatter formatter
= new Formatter();
for (byte b : hash)
{
formatter.format(
"%02x", b);
}
String result
= formatter.toString();
formatter.close();
return result;
}
//生成随机字符串
private static String createNonceStr() {
return UUID.randomUUID().toString();
}
//生成时间戳
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}

复制代码

HttpUtil代码

复制代码
public class HttpUtil {
public static Log logger
= LogFactory.getLog(HttpUtil.class);
//get请求
public static com.alibaba.fastjson.JSONObject doGet(String requestUrl) {
CloseableHttpClient httpClient
= HttpClients.createDefault();
CloseableHttpResponse response
= null;
String responseContent
= null;
com.alibaba.fastjson.JSONObject result
= null;
try {
//创建Get请求,
HttpGet httpGet = new HttpGet(requestUrl);
//执行Get请求,
response = httpClient.execute(httpGet);
//得到响应体
HttpEntity entity = response.getEntity();
//获取响应内容
responseContent = EntityUtils.toString(entity,“UTF-8”);
//转换为map
result = JSON.parseObject(responseContent);
}
catch (IOException e) {
logger.error(
“HttpUtil=Start");
logger.error(e.getMessage(),e);
logger.error(
"HttpUtil
=End”);
}
return result;
}
}
复制代码

 

(4)通过config接口注入权限验证配置

官方示例:

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

自己的代码:

其中的url不能硬编码写在后台,必须通过动态传递。

复制代码
$(function(){
var url = location.href.split(’#’).toString();//url不能写死
KaTeX parse error: Expected 'EOF', got '}' at position 2610: … } }) }̲);
…{wechat.appId}")
private String appId;
@Value(
" w e c h a t . a p p S e c r e t " < s p a n s t y l e = " l i n e − h e i g h t : 1.5 ; " > ) p r i v a t e S t r i n g a p p S e c r e t ; @ V a l u e ( < / s p a n > " {wechat.appSecret}"<span style="line-height:1.5;">) private String appSecret; @Value(</span>" wechat.appSecret"<spanstyle="lineheight:1.5;">)privateStringappSecret;@Value(</span>"{wechat.url.accessToken}")
private String accessTokenUrl;
@Value(
"${wechat.url.apiTicket}")
private String apiTicketUrl;
//微信参数

private String accessToken;
private String jsApiTicket;
//获取参数的时刻
private Long getTiketTime = 0L;
private Long getTokenTime
= 0L;
//参数的有效时间,单位是秒(s)
private Long tokenExpireTime = 0L;
private Long ticketExpireTime
= 0L;

//获取微信参数
@RequestMapping("/wechatParam")
@ResponseBody
public Map<String, String> getWechatParam(String url){
    //当前时间
    long now = System.currentTimeMillis();
    log.info("currentTime====>"+now+"ms");

    //判断accessToken是否已经存在或者token是否过期
    if(StringUtils.isBlank(accessToken)||(now - getTokenTime > tokenExpireTime*1000)){
        JSONObject tokenInfo = getAccessToken();
        if(tokenInfo != null){
            log.info("tokenInfo====>"+tokenInfo.toJSONString());
            accessToken = tokenInfo.getString("access_token");
            tokenExpireTime = tokenInfo.getLongValue("expires_in");
            //获取token的时间
            getTokenTime = System.currentTimeMillis();
            log.info("accessToken====>"+accessToken);
            log.info("tokenExpireTime====>"+tokenExpireTime+"s");
            log.info("getTokenTime====>"+getTokenTime+"ms");
        }else{
            log.info("====>tokenInfo is null~");
            log.info("====>failure of getting tokenInfo,please do some check~");
        }

    }

    //判断jsApiTicket是否已经存在或者是否过期
    if(StringUtils.isBlank(jsApiTicket)||(now - getTiketTime > ticketExpireTime*1000)){
        JSONObject ticketInfo = getJsApiTicket();
        if(ticketInfo!=null){
            log.info("ticketInfo====>"+ticketInfo.toJSONString());
            jsApiTicket = ticketInfo.getString("ticket");
            ticketExpireTime = ticketInfo.getLongValue("expires_in");
            getTiketTime = System.currentTimeMillis();
            log.info("jsApiTicket====>"+jsApiTicket);
            log.info("ticketExpireTime====>"+ticketExpireTime+"s");
            log.info("getTiketTime====>"+getTiketTime+"ms");
        }else{
            log.info("====>ticketInfo is null~");
            log.info("====>failure of getting tokenInfo,please do some check~");
        }
    }

    //生成微信权限验证的参数
    Map<String, String> wechatParam= makeWXTicket(jsApiTicket,url);
    return wechatParam;
}

//获取accessToken

private JSONObject getAccessToken(){
//String accessTokenUrl = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
String requestUrl = accessTokenUrl.replace(“APPID”,appId).replace(“APPSECRET”,appSecret);
log.info(
“getAccessToken.requestUrl====>”+requestUrl);
JSONObject result
= HttpUtil.doGet(requestUrl);
return result ;
}

//获取ticket

private JSONObject getJsApiTicket(){
//String apiTicketUrl = https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
String requestUrl = apiTicketUrl.replace(“ACCESS_TOKEN”, accessToken);
log.info(
“getJsApiTicket.requestUrl====>”+requestUrl);
JSONObject result
= HttpUtil.doGet(requestUrl);
return result;
}

//生成微信权限验证的参数
public Map<String, String> makeWXTicket(String jsApiTicket, String url) {
    Map<String, String> ret = new HashMap<String, String>();
    String nonceStr = createNonceStr();
    String timestamp = createTimestamp();
    String string1;
    String signature = "";

    //注意这里参数名必须全部小写,且必须有序
    string1 = "jsapi_ticket=" + jsApiTicket +
            "&noncestr=" + nonceStr +
            "&timestamp=" + timestamp +
            "&url=" + url;
    log.info("String1=====>"+string1);
    try
    {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(string1.getBytes("UTF-8"));
        signature = byteToHex(crypt.digest());
        log.info("signature=====>"+signature);
    }
    catch (NoSuchAlgorithmException e)
    {
        log.error("WeChatController.makeWXTicket=====Start");
        log.error(e.getMessage(),e);
        log.error("WeChatController.makeWXTicket=====End");
    }
    catch (UnsupportedEncodingException e)
    {
        log.error("WeChatController.makeWXTicket=====Start");
        log.error(e.getMessage(),e);
        log.error("WeChatController.makeWXTicket=====End");
    }

    ret.put("url", url);
    ret.put("jsapi_ticket", jsApiTicket);
    ret.put("nonceStr", nonceStr);
    ret.put("timestamp", timestamp);
    ret.put("signature", signature);
    ret.put("appid", appId);

    return ret;
}
//字节数组转换为十六进制字符串
private static String byteToHex(final byte[] hash) {
    Formatter formatter = new Formatter();
    for (byte b : hash)
    {
        formatter.format("%02x", b);
    }
    String result = formatter.toString();
    formatter.close();
    return result;
}
//生成随机字符串

private static String createNonceStr() {
return UUID.randomUUID().toString();
}
//生成时间戳
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}


页面js解决二次分享问题:


 

				
				

你可能感兴趣的:(学习)