总结之通过微信公众平台实现h5微信客户端自定义分享标题、描述和图标(前后端实现)

前置动作(后端开发)
步骤一:绑定域名

js安全域名配置很重要,前端的服务的域名,非常重要!
1、先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
JS接口安全域名需要和示例格式一模一样,不需要带http/https
备注:登录后可在“开发者中心”查看对应的接口权限。
2、需要开启开发者密钥,配置ip白名单(后端服务器ip,获取access_token等白名单不拦截)。
注意:ip白名单每天都在变化,可以参考官方获取ip方式
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html

设置JS接口安全域名后,公众号开发者可在该域名下调用微信开放的JS接口。

注意事项:

1、可填写五个域名或路径(例:wx.qq.com或wx.qq.com/mp),需使用由字母、数字、“-”或中文组成的合法域名,不支持IP地址、端口号及短链域名。

2、填写的域名须通过ICP备案的验证。

3、 将文件MP_verify_Pd7Rn8KfdBv1xmNh.txt(点击下载)上传至填写域名或路径指向的web服务器(或虚拟主机)的目录(若填写域名,将文件放置在域名根目录下,例如wx.qq.com/MP_verify_Pd7Rn8KfdBv1xmNh.txt;若填写路径,将文件放置在路径目录下,例如wx.qq.com/mp/MP_verify_Pd7Rn8KfdBv1xmNh.txt),并确保可以访问。

4、 一个自然月内最多可修改并保存五次,本月剩余保存次数:5

细节需要注意内容:
简单理解就是,前端h5项目运行的服务器域名,注意是域名,不是IP!

有一个txt文件要放置在提供的域名目录下,可以是根目录,也可以指定目录下面,配置好之后,直接浏览器地址栏访问这个路径,能打开就成功了,此处还有一个坑:

如果把这个txt文件放置在根目录,你的h5访问路径就不能带路径,也就是放置在根路径下面,http://xxx,xxx/index.html是没有问题的,如果h5项目是http://xxx.xxx/mp/index.html,这是行不通;

同理,如果你把这个txt文件放置在某个文件下,如:http://xxx.xxx/mp,放在mp文件夹下,那你的h5也要放在这个路径下面,http://xxx.xxx/mp/index.html;不然肯定有问题;

参考链接:
https://www.cnblogs.com/web-wjg/p/11346656.html
https://www.csdn.net/tags/OtDacgwsNDE0ODUtYmxvZwO0O0OO0O0O.html
https://www.mk2048.com/blog/blog_kijhh0j20hab.html

步骤二:引入JS文件

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

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

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

步骤三: 从后端获取权限配置签名

要从后端获取如下内容:

{
    "traceID": "09a3cad4-f426-4167-a375-c0676b4709e",
    "retCode": 200,
    "retMsg": "success",
    "data": {
        "signature": "a42a05f53400e380a000ef3832740f804ab",
        "appId": "wx6d67b63",
        "jsapi_ticket": "O3SMpm8bG7kJnF36aXbe8-83NpQ5KpEh_hfAfmkSN73KjH2CcJdtqwyli__Tj7uujod5sK7L6T69JQ",
        "url": "https://xxxxxx分享地址",
        "nonceStr": "66e4a737-ca38-467d-a53f-6d5e4d24b0b1",
        "timestamp": "1650878949"
    }
}
java签名算法可以下载微信公众平台demo
获取签名算法中,需要开发者传入 jsapi_ticket 和 url ,其中 jsapi_ticket 需要通过 http://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=ACCESS_TOKEN 接口获取,url 为调用页面的完整 url 
注意:
1. jsapi_ticket 的有效期为 7200 秒,开发者必须全局缓存 jsapi_ticket ,防止超过调用频率。

因为微信公众平台java的demo只实现了签名算法,还需要自己去获取jsapi_ticket
jsapi_ticket的获取又需要依赖access_token故贴出实现代码如下:

jspi_ticket应该失效前通过看门狗去获取更新,让它一直有效,这里是通过缓存方式,但并发很高时,可以发生缓存穿透,一瞬间耗光获取access_token的次数(可能性极低)

    /**
     *  常量appId
     **/
    private static String APP_ID = "wx673b63";
    /**
     *  常量appSecret 开发者密钥
     **/
    private static String APP_SECRET = "89168a79f7884";
    /**
     * 常量redis缓存超时 单位秒 微信有效期2小时
     **/
    private  static int TICKET_TIMEOUT = 30*60;
    /**
     * 微信 access_token 地址
     **/
    private static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
    /**
     * 微信 ticket 地址
     **/
    private static String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
    /**
     * 微信 jsApiTicket redis key
     **/
    private static String REDIS_TICKET = "jsApiTicket_";

    @Autowired
    public RedisTemplate redisTemplate;

    /**
    * @Description 微信分享,获取前端JS-SDK配置

    **/
    @Override
    public ResponseResult getWeiXinConfig(String url){
        //wxInfo[0] appId
        //wxInfo[1] appsecret
        String[] wxInfo = new String[]{APP_ID,APP_SECRET};
        String jsapi_ticket = "";

        //获取jsapi_ticket
        String ticketResString = getShareJsApiTicket(wxInfo);

        //解析ticket
        if (StringUtils.isNotEmpty(ticketResString)) {
            Integer code = (Integer) JSONPath.read(ticketResString, "$.errcode");
            if (code == 0) {
                jsapi_ticket = JSONObject.parseObject(ticketResString).get("ticket").toString();
            }
        }

        //返回为空,无法获取ticket
        if (StringUtils.isEmpty(jsapi_ticket)) {
            throw new TikTokListServiceException(ResultEnum.WEIXIN_TICKET_ERROR);
        }
        // 注意 URL 一定要动态获取,不能 hardcode
        Map ret = WeiXinSignUtil.sign(jsapi_ticket, url,wxInfo[0]);

        return ResultUtil.getResult(ResultEnum.SUCCESS, ret);
    }

    /**
     * @Description 微信分享,获取JsapiTicket

     **/
    private String getShareJsApiTicket(String[] wxInfo) {
        String jsApiTicket = "";
        //jsapi_ticket 的有效期为 7200 秒,必须全局缓存 jsapi_ticket ,防止超过调用频率。access_token 次数2000
        /**
        * 考虑并发情况
        * 1、并发后一个access_token获取,在没有获取到ticket之前,前一个access_token 失效,ticket就无法获取。
        * 考虑后解决方案:
        * 微信公众平台已解决:中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器可对外继续输出的老access_token,
        * 此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡
        *
        * 2、以后多次出现200+请求同时进来的时候,缓存失效,去请求微信,200*n > 2000后,使用次数就被限制
        * 考虑后解决方案:(未实施)
        * a.使用看门狗线程在缓存要过期时,生成新的ticket,替换缓存,请求一直命中缓存
        * b.在缓存失效后加双重检查锁,生成缓存前只允许一个线程操作对微信请求
        *
        * 3、后续开发注意 微信运营描述:access_token可能大于2小时,也有可能小于两小时
        *
        **/
        try {
            jsApiTicket = (String) redisTemplate.opsForValue().get(REDIS_TICKET+wxInfo[0]);
        }catch (Exception e){
            e.printStackTrace();
        }

        if(StringUtils.isNotEmpty(jsApiTicket)){
            log.warn("ticket from redis jsApiTicket: " + jsApiTicket);
            return jsApiTicket;
        }

        //获取accessToken
        String accessToken = getWeiXinAccessToken(wxInfo);
        if (StringUtils.isEmpty(accessToken)) { // 获取 accessToken 失败
            return null;
        }
        //ticket请求
        String url = TICKET_URL+"?access_token="+ accessToken + "&type=jsapi";
        //获取ticket
        jsApiTicket = httpReqExecute(url);
        log.warn("ticket from weixin api jsapiTicket is: " + jsApiTicket);

        if(StringUtils.isNotEmpty(jsApiTicket)) {
            // 向redis里写内容,第二个参数为过期时间,单位为:秒
            redisTemplate.opsForValue().set(REDIS_TICKET+wxInfo[0],jsApiTicket,TICKET_TIMEOUT, TimeUnit.SECONDS);
            return jsApiTicket;
        }
        return null;
    }

    /**
     * @Description 微信分享,获取access_token

     **/
    private String getWeiXinAccessToken(String[] wxInfo){
        String url = ACCESS_TOKEN_URL+"?grant_type=client_credential&appid="
                + wxInfo[0] + "&secret=" + wxInfo[1];

        String result = this.httpReqExecute(url);
        log.warn("from weixin api accessToken: " + result);
        Integer code = null;
        try {
            code = (Integer) JSONPath.read(result, "$.errcode");
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        try {
            if(StringUtils.isNotEmpty(result)) {
                // 解析access_token
                String accessToken = JSONObject.parseObject(result).get("access_token").toString();
                return accessToken;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    /**
    * @Description HTTP远程调用
    **/
    private String httpReqExecute(String url) {
        String result = "";
        DefaultHttpClient httpclient = null ;
        try {
            httpclient = new DefaultHttpClient();

            HttpPost httppost = new HttpPost(url);
            // 执行
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            if(entity != null && response.getStatusLine().getStatusCode() == 200){
                result =  EntityUtils.toString(entity, "UTF-8");
            }
        } catch (Exception e) {
            log.error(" 微信分享 调用微信 API 失败!", e);
        } finally { // 关闭连接,释放资源
            httpclient.getConnectionManager().shutdown();
        }
        return result;
    }
步骤四:通过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接口列表
});

分享接口
请注意,原有的 wx.onMenuShareTimeline、wx.onMenuShareAppMessage、wx.onMenuShareQQ、wx.onMenuShareQZone 接口,即将废弃。请尽快迁移使用客户端6.7.2及JSSDK 1.4.0以上版本支持的 wx.updateAppMessageShareData、wx.updateTimelineShareData接口。

自定义“分享给朋友”及“分享到QQ”按钮的分享内容(1.4.0)

wx.ready(function () {   //需在用户可能点击分享按钮前就先调用
  wx.updateAppMessageShareData({ 
    title: '', // 分享标题
    desc: '', // 分享描述
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () {
      // 设置成功
    }
  })
}); 

自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容(1.4.0)

wx.ready(function () {      //需在用户可能点击分享按钮前就先调用
  wx.updateTimelineShareData({ 
    title: '', // 分享标题
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () {
      // 设置成功
    }
  })
}); 

常见2个错误及解决方法

invalid signature签名错误。建议按如下顺序检查:

1、确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
总结之通过微信公众平台实现h5微信客户端自定义分享标题、描述和图标(前后端实现)_第1张图片

2、确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。

3、确认url是页面完整的url(请在当前页面alert(location.href.split(‘#’)[0])确认),包括’http(s)/‘部分,以及’?‘后面的GET参数部分,但不包括’#'hash后面的部分。

4、确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。

确保一定缓存access_token和jsapi_ticket。

5、确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去’#‘hash部分的链接(可用location.href.split(’#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。

the permission value is offline verifying这个错误是因为config没有正确执行,或者是调用的JSAPI没有传入config的jsApiList参数中。建议按如下顺序检查:

1、确认config正确通过。

2、如果是在页面加载好时就调用了JSAPI,则必须写在wx.ready的回调中。

3、确认config的jsApiList参数包含了这个JSAPI。

你可能感兴趣的:(前端,java及javaweb,微信,微信公众平台,前端)