Vue implements sharing your own website (h5 link) to WeChat to form a small card (super detailed)

Hello everyone, I am Xiongxiong.

Insert image description here

the latest update


A problem was discovered at 23:58:30 on December 24, 2022. It took a long time to solve it. The problem is as follows:

  1. When I sent the link directly to WeChat and then opened it, I found that it was still a link when I shared it.
  2. When I shared the link to QQ, I found that it was in the form of a custom card.
  3. When I share the QQ card to WeChat, I open the share to WeChat, which is in the form of a customized card.

I have been looking at this problem for a long time. Taobao asked someone to spend 80 yuan to solve it, but they refunded it to me. I asked all the major technical groups and couldn't solve it. The CSDN bounty Q&A also failed to solve it. Finally, I found out: WeChat does not support direct communication
. Enter the link to share. Otherwise, you will still be sharing the link. You need to enter from the WeChat entrance. For example, first generate a QR code for the content, then scan it in and share it, and that’s it! ! !

Preface

When we share official account information to WeChat or a group, a small card will appear, as shown below:
Insert image description here

However, this kind of small card can only be implemented through the WeChat interface. For example, the content we share from official accounts and mini programs can be like this. If we share our blog to WeChat, only a link will appear.

Insert image description here
So, let me ask you, if I share a link like this, would you click on it? Do you think this is a phishing link?

Today, let’s take a look at how to create a sharing card for our own website that is the same as WeChat.

Preparation

  • Register a public account, which needs to be certified (enterprise certification)
  • Prepare your site, what is displayed on the front end vue, and other things can be converted accordingly.
  • The backend is javaimplemented in other languages, and you can just convert it yourself.

Please note that a public account can be a subscription account or a service account, but it must be authenticated by the enterprise. Although some individuals can be authenticated, they do not have the authority to call the sharing interface.

Front-end business implementation (super detailed)

weixin-js-sdkThe help document is here, you can withdraw it and read it, so that it will not seem so unfamiliar after you see it later~
Help document

Let’s introduce the implementation steps below:

  1. Open the WeChat public platform and fill in the "JS interface security domain name" in the "Function Settings" of "Official Account Settings".
    Insert image description here
    If you don’t set it up, you will be blocked and unable to use it. You can take a closer look at how to set it up. The third point is the most important:
    Insert image description here
  2. In [Basic Configuration], configure your ipwhitelist. You can’t get it without setting it access_token. If you don’t set it up, toeknthere’s no need to talk about it.

Insert image description here
3. In vuethe project, install weixin-js-sdkthe following dependencies:

npm install weixin-js-sdk --save
  1. Write code in the page that needs to be shared vue, and first introduce the installed dependencies.
// 引入wxjs
import wx from "weixin-js-sdk"; 
  1. methodsImplement the sharing function in :
getShareInfo() {
    
    
      //获取url链接(如果有#需要这么获取)
      var url = encodeURIComponent(window.location.href.split("#")[0]);
 		//获取url链接(如果没有#需要这么获取)
     // var url = encodeURIComponent(window.location.href);

      getSing(url).then(res => {
    
    
        wx.config({
    
    
          debug: false, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。
          appId: res.data.appId, // 必填,公众号的唯一标识
          timestamp: parseInt(res.data.timestamp), // 必填,生成签名的时间戳
          nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
          signature: res.data.signature, // 必填,签名
          jsApiList: [
            "updateAppMessageShareData",
            "updateTimelineShareData"
          ] // 必填,需要使用的 JS 接口列表
        });
        wx.ready(() => {
    
    
          var shareData = {
    
    
            title: "每日新闻",
            desc: "2022年12月20日21:47:55每日新闻",
            link: window.location.href,
            imgUrl: "https://blogobs.88688.team/blog/l-logo-y.jpg"
          };
          //自定义“分享给朋友”及“分享到QQ”按钮的分享内容
          wx.updateAppMessageShareData(shareData);
          //自定义“分享到朋友圈”及“分享到 QQ 空间”按钮的分享内容(1.4.0)
          wx.updateTimelineShareData(shareData);
        });
        //错误了会走 这里
        wx.error(function (res) {
    
    
          console.log("微信分享错误信息", res);
        });
      });
    },

Code description:

  • url It is the link to the page we want to share, and it needs to be passed to the backend for encrypted signature (we will look at the backend code later)
  • getSingThe method is the signature method used by the backend. For security reasons, all configkey information in initialization is retrieved from the backend.
  • jsApiListIt is a list of methods of the functions we need to implement, separated by commas.
  1. createdCall the method in getShareInfo:
// 调用分享的事件
    this.getShareInfo();

That’s all the front-end content, let’s take a look at what operations the back-end does.


Backend code implementation (super detailed)

  1. Acquisition token: Why do you need to obtain it token? During the development of the WeChat public account, no matter what operation you do, you need this token, and the validity time is 7200s, which is two hours. It will expire after two hours. The following is tokenthe code obtained in java:
 /**
     * 获取access_token的值
     * @return
     */
    @GetMapping("/getToken")
    public String getToken() {
    
    
        String token = "";
        String path = "token?grant_type=client_credential&appid=" + APPID + "&secret=" + APPSECRET;
        String body = HttpUtil.createGet(WX_GZH_API + path)
                .execute()
                .body();
        log.info("获取了token,返回数据" + body);
        JSONObject object = JSON.parseObject(body);
        //获取token
        token = object.getString("access_token");
        //失效时间
        String expires_in = object.getString("expires_in");
        //将token值的值放在redis里面
        redisService.setCacheObject("gzh_access_token", token,7190,TimeUnit.SECONDS);
        return token;

    }

WX_GZH_API

//公众号请求的地址
    public static String WX_GZH_API = "https://api.weixin.qq.com/cgi-bin/";

APPID Just APPSECRETreplace it with your own.

  1. Obtain api_ticket, this is used in the signature, just request the interface directly to obtain it.
/**
     * 获取jsapi_ticket
     * @return
     */
    @GetMapping("/getJsapiTicket")
    public String getJsapiTicket() {
    
    
        //获取redis里面的token
        Object access_token = redisService.getCacheObject("gzh_access_token");
        if (access_token==null) {
    
    
            access_token = getToken();
        }
        String path = "ticket/getticket?access_token=" + access_token.toString() + "&type=jsapi";
        String body = HttpUtil.createGet(WX_GZH_API + path)
                .execute()
                .body();
        log.info("获取了JsapiTicket,返回数据" + body);
        JSONObject object = JSON.parseObject(body);
        //获取ticket
        String ticket = object.getString("ticket");
        //错误码
        Integer errcode = object.getInteger("errcode");
        if(errcode==0){
    
    
            //将ticket值的值放在redis里面
            redisService.setCacheObject("gzh_ticket", ticket,7190,TimeUnit.SECONDS);
        }
        return ticket;
    }

I have written cache for these two methods, and is the expiration time, and when using it, I will judge whether there is a value in the cache. If not, we will request to get it again instead of requesting it every time, which will cause The problem of frequent restriction of interface requests.

  1. Start signing:

    /**
     * 开始签名
     */
    @GetMapping("/getSing")
    public ResponseResult getSing(String url){
    
    
        //从redis里面获取ticket
        Object ticket = redisService.getCacheObject("gzh_ticket");
        if(ticket==null){
    
    
            ticket = getJsapiTicket();
        }
        Map<String, String> ret = WeChatUtils.sign(ticket.toString(), url);
        JSONObject objectData = new JSONObject();
        for (Map.Entry entry : ret.entrySet()) {
    
    
            objectData.put(entry.getKey().toString(),entry.getValue());
        }
        objectData.put("appId", APPID);
        return ResponseResult.success(objectData);
    }

Several signature tool classes are as follows:

//******************************************
    // 公众号网页开发
    //******************************************
    public static Map<String, String> sign(String jsapi_ticket, String url) {
    
    
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写,且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        System.out.println(string1);

        try
        {
    
    
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        }
        catch (NoSuchAlgorithmException | 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);

        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 create_nonce_str() {
    
    
        return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
    
    
        return Long.toString(System.currentTimeMillis() / 1000);
    }

The encrypted signature interface request is as follows:
Insert image description here
Then we implemented it, you can try yours.

Guess you like

Origin blog.csdn.net/qq_34137397/article/details/128399496