网页分享到微信自定义标题,内容和图片

@(I-前端学习)

网页分享到微信中自定义标题,内容和图片

随便说说:

网页现在也可以通过微信中直接打开,这就是用到时微信的浏览器,也可以通过微信浏览器中右上角进行分享到朋友,朋友圈,QQ等。这是需要微信的JSSDK的机制所以还是要进行一些配置才可以,而这些配置是需要微信公众号的appId和appsecret的,所以如果没有这些,也是不能进行自定义的。

实现过程

  1. 首先可以先阅读以下微信的JS-SDK的说明文档
    微信JS-SDK说明文档
  2. 绑定域名,登录微信公众平台,进入“公众号设置”的功能设置里面填写js接口安全域名,这个是要填写的是你微信浏览器要打开的域名地址。不能添加IP地址。
  3. 引入js文件
  4. 在需要调用js接口的页面接入JS文件 http://res.wx.qq.com/open/js/jweixin-1.2.0.js
  5. 通过config接口注入权限并验证配置
  6. 这一步算是整个步骤中最关键的一步,必须正确的配置信息才可以进行调用JS-SDK。
wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
});

下面讲如何获取 timestamp, noceStr(记得这个驼峰结构),singature

获取配置

先说说最烦人的singature,对于初学小程序的简直要了老夫的命,这是啥玩意,还是签名,所以我会把自己踩的坑给大家说一下。
获取签名实际是需要四步

1. 根据appId和appsecret获取access_token;
2. 使用access_token获取jsapi_ticket;
3. 使用时间戳,随机数,jsapi_ticket和要访问的url按照签名算法拼接字符串;
4. 对第三步的字符串进行SHA1加密,得到签名;
第一步,获取access_token

appId和appsecret可以在微信公众平台--开发-基本配置中查找

public static String getAccess_token(String appId, String appSecret){

        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
        String accessToken = null;
        try
        {
            URL urlGet = new URL(url);
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
            http.setRequestMethod("GET"); // 必须是get方式请求
            http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            http.setDoOutput(true);
            http.setDoInput(true);
            System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
            System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
            http.connect();
            InputStream is = http.getInputStream();
            int size = is.available();
            byte[] jsonBytes = new byte[size];
            is.read(jsonBytes);
            String message = new String(jsonBytes, "UTF-8");
            JSONObject jsonObj = JSONObject.fromObject(message);
            accessToken = jsonObj.getString("access_token");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return accessToken;
    }
第二步 获取jsapi_ticket
/**
     * 获得ACCESS_TICKET
     * 
     * @Title: ACCESS_TICKET
     * @Description: 获得ACCESS_TICKET
     * @param @return 设定文件
     * @return String 返回类型
     * @throws
     */
    public static String getAccess_ticket(String access_token) {  
        String ticket = null;  
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ access_token +"&type=jsapi";//这个url链接和参数不能变  
        try {  
            URL urlGet = new URL(url);  
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();  
            http.setRequestMethod("GET"); // 必须是get方式请求  
            http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");  
            http.setDoOutput(true);  
            http.setDoInput(true);  
            System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒  
            System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒  
            http.connect();  
            InputStream is = http.getInputStream();  
            int size = is.available();  
            byte[] jsonBytes = new byte[size];  
            is.read(jsonBytes);  
            String message = new String(jsonBytes, "UTF-8");  
            JSONObject demoJson = JSONObject.fromObject(message);  
            System.out.println("JSON字符串:"+demoJson);  
            ticket = demoJson.getString("ticket");  
            is.close();  
        } catch (Exception e) {  
                e.printStackTrace();  
        }  
        return ticket;  
    }  
    

这里拿到对应的jsapi_ticket之后就可以进行参数排序和拼接字符串并加密

第三步:SHA1加密
public static String SHA1(String decript) {  
        try {  
            MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");  
            digest.update(decript.getBytes());  
            byte messageDigest[] = digest.digest();  
            // Create Hex String  
            StringBuffer hexString = new StringBuffer();  
            // 字节数组转换为 十六进制 数  
                for (int i = 0; i < messageDigest.length; i++) {  
                    String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);  
                    if (shaHex.length() < 2) {  
                        hexString.append(0);  
                    }  
                    hexString.append(shaHex);  
                }  
                return hexString.toString();  
       
            } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
            }  
            return "";  
    }  

加密算法转载自:http://www.open-open.com/lib/view/open1392185662160.html

第四步: 获取签名
public static void main(String[] args) {  
    //1、获取AccessToken  
    String accessToken = getAccessToken();  
      
    //2、获取Ticket  
    String jsapi_ticket = getTicket(accessToken);  
      
    //3、时间戳和随机字符串  
    String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//随机字符串  
    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳  
      
    System.out.println("accessToken:"+accessToken+"\njsapi_ticket:"+jsapi_ticket+"\n时间戳:"+timestamp+"\n随机字符串:"+noncestr);  
      
    //4、获取url  
    String url="http://www.luiyang.com/add.html";  
    /*根据JSSDK上面的规则进行计算,这里比较简单,我就手动写啦 
    String[] ArrTmp = {"jsapi_ticket","timestamp","nonce","url"}; 
    Arrays.sort(ArrTmp); 
    StringBuffer sf = new StringBuffer(); 
    for(int i=0;i<ArrTmp.length;i++){ 
        sf.append(ArrTmp[i]); 
    } 
    */  
      
    //5、将参数排序并拼接字符串  
    String str = "jsapi_ticket="+jsapi_ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;  
     
    //6、将字符串进行sha1加密  
    String signature =SHA1(str);  
    System.out.println("参数:"+str+"\n签名:"+signature);  
}  

改写之后的代码,json格式返回。

protected void doPost(HttpServletRequest request, HttpServletResponse response){
        
        //appId和appSecret
        String appId = "XXXXX";
        String appSecret = "XXXXX";
        
        //外部传入url获取url url需要是微信中打开的url否则会报错。
        String URL = request.getParameter("url"); 
        //转换url
        
        String url="";
        //需要转换解码url
        try {
            url = java.net.URLDecoder.decode(URL,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //获取access_token
        String aeecss_token = HttpUtil.getAccess_token(appId, appSecret);
        
        //获取access_ticket
        String aeecss_ticket = HttpUtil.getAccess_ticket(aeecss_token);
        
        
         //3、时间戳和随机字符串  
        String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//随机字符串  
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳  
          
        System.out.println("accessToken:"+aeecss_token+"\njsapi_ticket:"+aeecss_ticket+"\n时间戳:"+timestamp+"\n随机字符串:"+nonceStr);  
          
        
        //4、获取url  
        //5、将参数排序并拼接字符串  
        String str = "jsapi_ticket="+aeecss_ticket+"&noncestr="+nonceStr+"&timestamp="+timestamp+"&url="+url;  
         
        //6、将字符串进行sha1加密  
        String signature =SHA1(str);  
        System.out.println("参数:"+str+"\n签名:"+signature);  
        
        
        Map<String,String> map=new HashMap();
        map.put("appId",appId);
        map.put("timestamp",timestamp);
        map.put("accessToken",aeecss_token);
        map.put("ticket",aeecss_ticket);
        map.put("nonceStr",nonceStr);
        map.put("signature",signature);
        JSONObject jsonObject = JSONObject.fromObject(map);
        
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

        PrintWriter pw = null;
        try {
            pw = response.getWriter();
        } catch (IOException e1) {
            logger.error("**********reponse getWriter exception**********");
            e1.printStackTrace();
        }
        pw.write(jsonObject.toString());
        pw.close();
    }

这一段代码是改写了,获取签名后把所有的信息都返回json格式了。概要的都有了,这是就可以配置config了,此时应该是:

 $.ajax({
            url: 'http://10.25.74.68:8088',
            type: 'POST',
            dataType: 'json',
            //url需要编码传入而且要是完整的url除#之后的
            data: {"url":encodeURIComponent(window.location.href.split("#")[0])}
        })
        .done(function(res) {

            wx.config({
                debug: ture, //调试阶段建议开启
                appId: res.appId,//APPID
                timestamp: res.timestamp,//上面main方法中拿到的时间戳timestamp
                nonceStr: res.nonceStr,//上面main方法中拿到的随机数nonceStr
                signature: res.signature,//上面main方法中拿到的签名signature
                //需要调用的方法接口
                jsApiList: [ 'onMenuShareTimeline','onMenuShareAppMessage','onMenuShareWeibo','onMenuShareQQ','onMenuShareQZone']
            });
   }
注意:
  1. url一定要是完整的url(当前网页的URL,不包含#及其后面部分)最好是使用window.location.href.split("#")获取得到,如果传入固定的好像会报invalid signature错误,所以为了安全起见还是直接传入当前的url
  2. 这个签名的有效时间为7200秒,也就是2个小时,因此当超过两个小时候,再访问也会报invalid signature错误。但是这个我还没有遇见,并不知道这么解决,其他说是需要缓存access_token和access_ticket
  3. 另外还有一个错误:invalid url domain
    这个跟生成签名时用的url有关系,官网的说法是:
    invalid url domain当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,如果使用了端口号,则配置的绑定域名也要加上端口号(一个appid可以绑定三个有效域名)
    这个url必须是:“公众号设置---功能设置----JS接口安全域名”中绑定的三个域名之一
  4. 如果以上配置都是正确,而且debug也设置为true了,在微信中访问连接会出现config:ok的界面,就说明配置成功了
  5. 有时也可以把ajax请求放在setTimeout中进行请求。

自定义标题,内容和图片

    wx.ready(function(){
                // alert("我已经进来了");
                wx.onMenuShareTimeline({
                    title: title, // 分享标题
                    link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: "//upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享图标
                    success: function () {
                        // alert("成功")
                        // 用户点击了分享后执行的回调函数
                    }
                });
                wx.onMenuShareAppMessage({
                    title: title, // 分享标题
                    desc: descContent, // 分享描述
                    link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: "//upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function () {
                        // alert("成功")
                        // 用户点击了分享后执行的回调函数
                    }
                });
                wx.onMenuShareQQ({
                    title: title, // 分享标题
                    desc: descContent, // 分享描述
                    link: window.location.href, // 分享链接
                    imgUrl: "//upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享图标
                    success: function () {
                        // alert("成功")
                        // 用户确认分享后执行的回调函数
                    },
                    cancel: function () {
                        // alert("失败")
                        // 用户取消分享后执行的回调函数
                        // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
                    }
                });
            });
注意:
  1. 应该把自定义的内容卸载wx.ready(
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
    )里面,
  2. link该链接域名或路径必须与当前页面对应的公众号JS安全域名
  3. imgUrl:最好是绝对地址的图片,相对位置好像出不来 比如:'../assets/image/213.png'这样是出不来的

验证工具:
微信公众平台接口调试工具
微信 JS 接口签名校验工具

参考:
解决微信JS-SDK扫一扫功能接入以及出现签名无效 invalid signature
微信JS-SDK获取signature签名以及config配置

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350