iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >微信公众号开发入门
  • 888
分享到

微信公众号开发入门

微信小程序 2023-09-03 08:09:07 888人浏览 独家记忆
摘要

实在是太折腾,太难懂了。也太坑了。 下面是这几天来,有关微信公众号的工作总结。算不上全面,只是作为一个初学者的记录,仅以备忘。 一、微信公众号开发,开发什么? 公众号与小程序不同。小程序类似手机APP

实在是太折腾,太难懂了。也太坑了。

下面是这几天来,有关微信公众号的工作总结。算不上全面,只是作为一个初学者的记录,仅以备忘。

一、微信公众号开发,开发什么?

公众号与小程序不同。小程序类似手机APP,独立开发,微信只是提供了一个入口;而公众号则基本上是在微信框架内。微信公众号本质上是用户的一个联系人,只不过是比较特殊的联系人而已。通过微信提供的公众号管理后台,无须任何编程,就可以很快搭建出一个像模像样的公众号,菜单、机器人客服、文章更新,五脏俱全。

但是,如果要更强的功能,就需要开发了。比如,机器人客服。通过公众号管理后台,可以定义一些自动回复语句,但毕竟不够智能,这时我们可以在互联网上搭建服务器,提供相应服务。当然,这需要准备好网址、域名。

第二个,菜单。公众号的菜单项点击后,可以是回复一些消息,或跳转到小程序,或打开一张网页。打开网页的话,如果是未经认证的公众号,只能打开公众号里的素材,或已经发表在当前公众号里的文章或图片、视频之类;而经过认证的公众号,则可以直接打开任意网址。这些网页,通常都会是部署在互联网上的所谓微信网页,它们使用了微信js-SDK,上面有各种微信的元素,比如扫一扫啦,分享到朋友圈啦,诸如此类。那这部分,当然需要开发。

还有就是给关注者发送消息。我认为这是微信公众号最大的卖点。比如说,我关注了某个公众号,通过这个公众号的菜单,打开了相关小程序办事,事情有了进展,系统就可以通过这个公众号给我发消息,提示一下当前办事进度。我认为这是公众号开发中最值得做的工作。

当然,还有可以通过程序自动在公众号上发表文章。不过这种事情,人工在公众号管理后台也能做,无非动动手而已。

二、开发铺垫

在开发之前,先要了解一下有关的规约。建议也阅读一下开发文档的开始部分:微信公众平台开发概述

1、公众号的分类

衣穿三色,食分五等。所谓微信公众号,分为订阅号和服务号。个人只能申请订阅号,企业可以申请订阅号和服务号。然后公众号又有经过认证和未经认证之分。公众号类型,是否经过认证,决定了许多微信服务能否被调用。未经认证,基本上没有啥可以玩的。而且不幸的是,个人申请的订阅号,根本不能进行微信认证,直接堵死了这扇门。

那怎么开发?微信又很“贴心”地提供了测试账号这个机制。我们可以先不申请公众号,而是先申请一个测试账号,用这个账号来测试微信服务接口。测试账号所有微信服务接口都能访问。然鹅!像微信网页这些,需要跑在手机上才能看到效果,而如果用的是测试账号的话,有些东西是渲染不出来的。比如所谓的微信开放标签(就是微信自己定义的,类似html的标签)。

订阅号与服务号侧重点不同。按我的理解,订阅号侧重发表文章,服务号则侧重针对性发通知消息。总的来说,服务号功能比订阅号要强大许多。
在这里插入图片描述
表面上看,订阅号每天可以群发1条消息,而服务号只能每个月发4条,订阅号要强。问题是,群发消息有啥用?我们网上办事,要的是针对本人的消息。只有服务号才能发送这针对性的通知消息。
在这里插入图片描述
文档里,管这种消息叫模板消息。为啥叫模板消息呢?是因为这种消息要结合模板生成。就像我们的手机短信。做过手机短信开发都知道,手机短信可不是随随便便就能发送的,因为众所周知的原因,怕有违法、出格的内容,要有所谓的模板,即短信格式是固定的,许多字眼也都是固定的,我们每次发送时只需往里面填一些内容。这个模板要事先创建好并通过电信运营商审批。微信这个消息也要使用模板,调用发送接口时,需要将模板ID作为参数传递。

目前,小程序的模板消息功能已经废弃了,改用所谓“统一服务消息”,其实就是改用服务号进行发送。就是说,小程序如果要给用户发送通知的话,必须要对应一个服务号。

不过世界上还有一种东西叫做订阅消息。公众号里叫做订阅通知,小程序里叫订阅消息。分为一次性和长期2种。订阅消息要用户主动订阅。比如用麦当劳小程序订餐,每次付款以后,它都会问你,要不要接受取餐通知。长期性只对某些民生、医院类的公众号开放。这个在申请公众号时就给定了性。不要心存侥幸,低估了微信折腾人的本事。否则,发送时对方总是收不到,错误提示可能没有;就算有,可能也专业得很,根本想不到是账号类型的问题。

模板消息和订阅消息有啥区别呢?订阅消息不就是要用户手动订阅一下嘛,也没啥。问题是,这就一定要用手机来操作啊。假如我是通过PC端来办事,想手机收到提醒呢?订阅消息就完犊子了。(是不是这样啊?微信PC端也能进行订阅操作?)

2、公众号调试工具

就是微信开发者工具。注意是开发者工具,而不是开发工具。这个工具,对于小程序来说,的确就是一个开发工具;而对于公众号来说,只是一个调试工具,并不能通过它来键入什么代码;而且只是微信网页的调试工具。此时它只是一个微信浏览器。方法是在微信开发者工具的顶部输入微信网页地址即可浏览,调试,跟普通浏览器按下F12差不多。

3、查看微信网页运行结果

公众号通过微信客户端就能看到。这里说的查看结果,是指查看 微信网页 的运行结果。虽然有网页二字,但这不是普通的网页,用一般浏览器访问,虽然不报错,但看不到什么效果,应该通过微信浏览器或者微信开发者工具来运行。注意手机上并没有一个app叫微信浏览器,这是微信隐含的。怎么召唤它呢?可以将微信网页的地址发给微信某个好友,比如“文件传输助手”,然后在聊天记录里点击这个网址,就会用微信浏览器打开。绝逼是微信浏览器,QQ浏览器都不好使。

4、开发文档

基于微信做二次开发,网上查资料基本没什么卵用,最好还是老老实实地啃微信官方开发文档

公众号开发文档在 公众号管理后台 - 设置与开发 - 开发者工具 - 开发文档 打开。

微信有两个平台,小程序的叫“微信开发开放平台”,公众号的叫“微信开发公众平台”。

5、一些术语

1)管理员及运营者
开发过程中,免不了要访问微信公众号管理后台,对某些设置作出修改或设置,但是改变设置必须扫二维码进行身份认证。这就尴尬了。申请公众号的人是管理员,但他不一定参与开发。如果下下都惊动这个大老板来扫二维码不方便,甚至不可能。可以把开发人员加到运营者名单里,自己扫码就行。运营者分长期和短期2种,应该是长期运营者,权限才够大。

可在 微信公众号管理后台 - 设置与开发 - 人员设置 里设置。

2)IP白名单
在开发过程中,我们需要访问微信服务器,比如获取token之类。发出请求的IP,需要在白名单上。这个IP,是指互联网IP。假如我们在公司内部开发,那这个IP是公司上网的IP。问题是,这个IP经常变。我不知道有什么好办法,所以基本上是每天改一次白名单。

IP白名单是给我们在本地调试微信开发者工具用的。手机运行不需要。

在这里插入图片描述

3)开发者微信号
公众号管理后台 - 设置与开发 - web开发者工具,将我们开发人员的微信号加进去。这是开发微信网页要用到的。因为微信开发者工具需要微信号登录。

4)JS接口安全域名
公众号管理后台 - 设置与开发 - 公众号设置 - 功能设置。

也是微信网页开发需要。我们的页面,需要放在这个域名里,微信的js-sdk才可以使用。

填写这个域名的时候,需要下载一个txt文件放到域名下,微信验证域名真伪才能保存。不过填好以后,我们在本地开发时,可以修改host文件,将本机ip映射为该域名。毕竟是前端的一个东西,js-sdk本身需要微信浏览器支持,它也判断不出来请求来自于哪个IP,我们传给它什么它都信。

5)微信开放标签
类似HTML的,微信独有的标签。如

跳转小程序:<wx-open-launch-weapp>跳转App:<wx-open-launch-app>服务号订阅通知:<wx-open-subscribe>音频播放:<wx-open-audio>

三、微信网页开发

1、概述

微信网页真的就是一张张网页,只不过,它引用了微信提供的JS库,可能使用微信独有的,类似html的所谓开放标签。并且这个微信网页似乎在普通浏览器上运行,虽不会报错,但似乎看不到什么效果,只能运行在微信浏览器或微信开发者工具上。

以下是一张微信网页(Spring Boot下,结合了thymeleaf)

DOCTYPE html><html lang="en" xmlns:th="Http://www.thymeleaf.org"><head>    <title>wechattitle>    <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js">script>    <script src="./libs/Jquery.min.js">script>    <style>        .sao{            text-align: center;width: 100%;height:5.5em;background-color: #DDD;line-height: 5.5em;            cursor:pointer;        }        .block{            height: 100px;            border:solid 1px red;        }    style>head><body>    <div class="sao qr_btn">扫一扫div>        <div class="block">                <wx-open-subscribe th:template="${template}" id="subscribe-btn">            <script type="text/wxtag-template" slot="style">                <style>                    .subscribe-btn {                        color: #fff;                        background-color: #07c160;                    }                </style>            script>            <script type="text/wxtag-template">                <button class="subscribe-btn">                    模版消息订阅                </button>            script>        wx-open-subscribe>    div>body><script th:inline="javascript">//微信验证    wx.config({        debug: true,        appId: '',        timestamp: '',        nonceStr: '',//随机串        signature: '',        jsapiList: ['chooseImage','scanQRCode','updateAppMessageShareData','updateTimelineShareData'],//需要使用的微信js-sdk函数列表        openTagList: ['wx-open-subscribe']//开放标签列表    });    wx.ready(function () {        // 微信分享 -- 分享给朋友        wx.updateAppMessageShareData({            title: '分享给您的猪朋狗友吧',            desc: '独食难肥',            link: location.href.split('#')[0],            imgUrl: "http://test.duduchuhai.com/images/share.png",            success: function(res) {                console.log(res);            }        });        // 微信分享 -- 分享到朋友圈        wx.updateTimelineShareData({            title: '分享到猪圈',            link: location.href.split('#')[0],            imgUrl: "http://test.duduchuhai.com/images/share.png",            success: function(res) {                console.log(res);            }        });    });    wx.error(function (res) {        console.log(res);      // res为微信返回的错误结果    });    // 微信扫一扫    $(".qr_btn").on('click', function() {        wx.scanQRCode({            needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,            scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有            success: function (res) {                var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果            }        });    });script><script>    var btn = document.getElementById('subscribe-btn');    console.log(btn);    btn.addEventListener('success', function (e) {        console.log('success', e.detail);    });    btn.addEventListener('error',function (e) {        console.log('fail', e.detail);    });script>html>

2、验证

微信网页运行时,首先要经过微信验证,然后才能正常使用微信各种功能。验证流程是,
1)凭appId和appSecret访问微信服务器获得token
2)用token访问微信服务器获得ticket
3)依次用ticket、随机串、时间戳、当前页面地址组合成一个字符串,然后对字符串进行sha散列运算,得到一个摘要
4)用摘要访问微信服务器获得签名
5)将 appId、时间戳、随机串、签名、本页面需要使用的微信函数、微信开放标签注册到微信

上面例子中,

    wx.config({        debug: true,        appId: '',        timestamp: '',//注意是秒,不是毫秒        nonceStr: '',//随机串        signature: '',//关键所在        jsApiList: ['chooseImage','scanQRCode','updateAppMessageShareData','updateTimelineShareData'],//需要使用的微信js-sdk函数列表        openTagList: ['wx-open-subscribe']//开放标签列表    });

为了得到这个JSON对象可不容易。appId在微信公众号管理后台可得到,每个公众号都有唯一一个appId;时间戳也容易得到;随机串是自己定的,相对比较容易;最麻烦的是这个签名signature,我调试了差不多1天,总是说非法签名。

获取这个json对象的java代码:

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import Redis.clients.jedis.Jedis;import javax.annotation.PostConstruct;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLConnection;import java.security.MessageDigest;import java.security.NoSuchAlGorithmException;import java.util.Date;import java.util.Random;import java.util.concurrent.locks.ReentrantLock;@Servicepublic class WxServiceImpl implements WxService {    @Override    public WxConfig getWxConfig(String url) {//url是微信网页地址        WxConfig wc = new WxConfig();//这个是自定义的对象,不必深究        wc.setAppId(APPID);        wc.setNonceStr(getNonceStr());//随机串        wc.setTimestamp((long) (new Date()).getTime() / 1000);//时间戳        wc.setSignature(getSignature(wc.getNonceStr(), wc.getTimestamp(), url));//签名        return wc;    }    @PostConstruct    void init() {            this.jedis = new Jedis(redis的IP, redis端口号);    }    private String getSignature(String nonceStr, long timestamp, String url) {//获取签名        String signature = null;        String ticket = getTicket();        if (ticket != null) {            String string1 = String.fORMat("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s",                    ticket,                    nonceStr,                    timestamp,                    url);            signature = getSha1(string1);        }        return signature;    }//redis对象    private Jedis jedis;//除了redis缓存,也用静态变量保存一份。不过,应用程序重启它们就消失了,并且不会自动过期//而从微信获取到的token和ticket有效期是7200秒    private String _ticket = null;    private String _token = null;//。为避免并发,使用锁机制,不要大家都去获取token和ticket    private ReentrantLock lockTok = new ReentrantLock();    private ReentrantLock lockTik = new ReentrantLock();    private String getTicket() {        String ticket = null;        String key = "ticket";        ticket = geTKEy(key, this._ticket);        if (ticket == null) {            //锁定。            lockTik.lock();            ticket = getKey(key, this._ticket);//再努力一把            if (ticket == null) {                String token = getToken();                if (token != null) {                    ticket = callGet(String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi",token), "ticket");                    if (ticket != null) {                        this._ticket = ticket;                        setKey(key, ticket);                    }                }            }            //解锁            lockTik.unlock();        }        return ticket;    }    private String getToken() {        String token = null;        String key = "token";        token = getKey(key, this._token);        if (token == null) {            lockTok.lock();            token = getKey(key, this._token);            if (token == null) {                token = callGet(String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",APPID,AppSecret),                 "access_token");                if (token != null) {                    this._token = token;                    setKey(key, token);                }            }            lockTok.unlock();        }        return token;    }    final static int EXPIRTED = 7200;    private String getKey(String key, String v) {        String value = null;        try {            value = jedis.get(key);        } catch (Exception ex) {            value = v;//如果无法从redis中读取则将候补变量值返回。但变量值可能有过期的问题            System.err.println(ex.getMessage());        }        return value;    }    private void setKey(String key, String value) {        try {            jedis.set(key, value);            jedis.expire(key, EXPIRTED);        } catch (Exception ex) {            System.err.println(ex.getMessage());        }    }    final static int NONCESTR = 16;//随机串的长度为16。这个数值是自己定的    private String getNonceStr() {// 生成随机字符串noncestr        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";        StringBuffer noncestr = new StringBuffer();        int limit = chars.length() - 1;        for (int i = 0; i < NONCESTR; i++) {            Random r = new Random();            int j = r.nextInt(limit);            noncestr.append(chars.substring(j, j + 1));        }        return noncestr.toString();    }    private static String getSha1(String string1) {        MessageDigest sha = null; // 此处的sha代表sha1        try {            sha = MessageDigest.getInstance("SHA");        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        }        byte[] md5Bytes = new byte[0];        try {            md5Bytes = sha.digest(string1.getBytes("UTF-8"));        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }        StringBuffer hexValue = new StringBuffer();        for (int i = 0; i < md5Bytes.length; i++) {            int val = ((int) md5Bytes[i]) & 0xff;            if (val < 16) {                hexValue.append("0");            }            hexValue.append(Integer.toHexString(val));        }        return hexValue.toString();    }public static String callGet(String api, String key) {//get的方式访问微信api        String re = null;        System.out.println(String.format("正在获取 %s : %s", key, api));        try {            URL url = new URL(api);            HttpURLConnection connection = (HttpURLConnection) url.openConnection();            connection.connect();            BufferedReader br = new BufferedReader(                    new InputStreamReader(connection.getInputStream(), "UTF-8"));            String line;            StringBuilder sb = new StringBuilder();            while ((line = br.readLine()) != null) {                sb.append(line);            }            br.close();            connection.disconnect();            JSONObject json = JSON.parseObject(sb.toString());            if (json.containsKey(key)) {                re = json.getString(key);            }            System.out.println(re);        } catch (Exception ex) {            ex.printStackTrace();            System.out.println(String.format("访问接口%s失败", api));        }        return re;    }}

3、调试

在微信开发者工具上,输入微信网页地址,运行,得到好多提示。对于微信公众号来说,微信开发者工具就是一个调试工具,一个开了调试模式的浏览器。但刚开始时,总是失败。表现在,我在例子中声明,需要用到下列微信函数:

    wx.config({        debug: true,        appId: '',        timestamp: '',//注意是秒,不是毫秒        nonceStr: '',//随机串        signature: '',//关键所在        jsApiList: ['chooseImage','scanQRCode','updateAppMessageShareData','updateTimelineShareData'],//需要使用的微信js-sdk函数列表        openTagList: ['wx-open-subscribe']//开放标签列表    });

结果从返回的信息看,我有权访问的函数为0。除此之外,就是到处提示什么“fail, the permission value is offline verifying”之类。

打开微信开发者工具调试模式:微信开发者工具中,顶部菜单“微信开发者工具” - 调试 - “调试微信开发者工具” - network,看这个preverify?_r=…的返回信息,结果是 {errcode: 63002, errmsg: “invalid signature”}!

难道是签名算法有问题?我在微信公众号管理后台上,用它们提供的微信 JS 接口签名校验工具,结果完全一致,因此不存在算法有误的问题。

4、填坑

后来发现是URL的问题。生成签名过程中,需要传递当前微信网页的URL参与构造一个字符串,然后散列处理后,传给微信服务器获得签名。问题是,这个URL该怎么写?由于我这个微信页面,名为index.html,一般访问时,习惯在浏览器上这样输入地址:http://www.abc.com,因此我也就把这个地址参与构造签名,结果就是一直提示签名无效。后来将地址写全:http://www.abc.com/index,结果一下子OK了。

但官方开发文档上是怎么写的?
在这里插入图片描述
不认真审题害死人。

四、向公众号订阅者发送模板消息

这个功能,在我们自己的服务器端调用微信接口来实现。

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import redis.clients.jedis.Jedis;import javax.annotation.PostConstruct;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLConnection;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Date;import java.util.Random;import java.util.concurrent.locks.ReentrantLock;@Servicepublic class WxServiceImpl implements WxService {    @Override    public String sendMess(String jsonStr) {        String re = null;        String token = getToken();        if(token != null) {            String api = String.format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s",token);            re = callPost(api, jsonStr);        }        return re;    }    @PostConstruct    void init() {        this.jedis = new Jedis(redis的IP, redis端口号);    }    private Jedis jedis;    private String _token = null;    private ReentrantLock lockTok = new ReentrantLock(); private String getToken() {        String token = null;        String key = "token";        token = getKey(key, this._token);        if (token == null) {            lockTok.lock();            token = getKey(key, this._token);            if (token == null) {                token = callGet(String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",AppId,AppSecret), "access_token");                if (token != null) {                    this._token = token;                    setKey(key, token);                }            }            lockTok.unlock();        }        return token;    }    final static int EXPIRTED = 7200;    private String getKey(String key, String v) {        String value = null;        try {            value = jedis.get(key);        } catch (Exception ex) {            value = v;//如果无法从redis中读取则将候补变量值返回。但变量值可能有过期的问题            System.err.println(ex.getMessage());        }        return value;    }    private void setKey(String key, String value) {        try {            jedis.set(key, value);            jedis.expire(key, EXPIRTED);        } catch (Exception ex) {            System.err.println(ex.getMessage());        }    }    private static String callPost(String api, String param) {        PrintWriter out = null;        BufferedReader in = null;        String result = "";        try {            URL realUrl = new URL(api);            // 打开和URL之间的连接            URLConnection conn = realUrl.openConnection();            // 设置通用的请求属性            conn.setRequestProperty("accept", "*/*");            conn.setRequestProperty("Content-Type", "application/json");            conn.setRequestProperty("connection", "Keep-Alive");            conn.setRequestProperty("user-agent",                    "Mozilla/4.0 (compatible; MSIE 6.0; windows NT 5.1;SV1)");            // 发送POST请求必须设置如下两行            conn.setDoOutput(true);            conn.setDoInput(true);            // 获取URLConnection对象对应的输出流            out = new PrintWriter(conn.getOutputStream());            // 发送请求参数            out.print(param);            // flush输出流的缓冲            out.flush();            // 定义BufferedReader输入流来读取URL的响应            in = new BufferedReader(                    new InputStreamReader(conn.getInputStream()));            String line;            while ((line = in.readLine()) != null) {                result += line;            }        } catch (Exception e) {            System.out.println("发送 POST 请求出现异常!" + e);            e.printStackTrace();        } finally {//使用finally块来关闭输出流、输入流            try {                if (out != null) {                    out.close();                }                if (in != null) {                    in.close();                }            } catch (IOException ex) {                ex.printStackTrace();            }        }        return result;    }    public static String callGet(String api, String key) {        String re = null;        System.out.println(String.format("正在获取 %s : %s", key, api));        try {            URL url = new URL(api);            HttpURLConnection connection = (HttpURLConnection) url.openConnection();            connection.connect();            BufferedReader br = new BufferedReader(                    new InputStreamReader(connection.getInputStream(), "UTF-8"));            String line;            StringBuilder sb = new StringBuilder();            while ((line = br.readLine()) != null) {                sb.append(line);            }            br.close();            connection.disconnect();            JSONObject json = JSON.parseObject(sb.toString());            if (json.containsKey(key)) {                re = json.getString(key);            }            System.out.println(re);        } catch (Exception ex) {            ex.printStackTrace();            System.out.println(String.format("访问接口%s失败", api));        }        return re;    }}

测试

    @Autowired    WxService service;    @Test    public void testSendMess(){        String json = "{\n" +                "    \"touser\":OPENID,\n" +                "    \"template_id\":模板ID,\n" +                "    \"data\":{\n" +                "        \"name01\": {\n" +                "            \"value\":\"韩擒虎女士\"\n" +                "        },\n" +                "        \"thing01\":{\n" +                "            \"value\":\"您的大头佛到货了\"\n" +                "        },\n" +                "        \"date01\": {\n" +                "            \"value\":\"2022-04-15\"\n" +                "        }\n" +                "    }\n" +                "}";        String re = service.sendMess(json);        System.out.println(re);    }

这个功能只有通过认证的服务号才能权限使用。但开发时候,可以通过申请一个测试账号来试验。需要在公众号管理后台创建一个模板。模板参考如下:
在这里插入图片描述
用户的OPENID也容易得到:
在这里插入图片描述
测试结果
在这里插入图片描述

五、小结

整个微信体系,东西很多很杂,各种自定义的术语,对于初接触者,晕头转向。然后提供的开发文档,洋洋洒洒,密密麻麻,只是一堆手册,等待你自己去查阅。许多东西,你根本不知道它是什么鬼,用来干啥的,文档只是泛泛地说应该怎么怎么弄,却又极少举例子。这就给初学者带来很大的困扰,人为制造了许多的障碍。

而且这种二次开发并没有什么意义。

微信公众号及小程序开发入门(二)

来源地址:https://blog.csdn.net/leftfist/article/details/124168423

--结束END--

本文标题: 微信公众号开发入门

本文链接: https://www.lsjlt.com/news/391839.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 微信公众号开发入门
    实在是太折腾,太难懂了。也太坑了。 下面是这几天来,有关微信公众号的工作总结。算不上全面,只是作为一个初学者的记录,仅以备忘。 一、微信公众号开发,开发什么? 公众号与小程序不同。小程序类似手机APP...
    99+
    2023-09-03
    微信 小程序
  • Java微信公众平台开发(1) 接入微信公众平台
    前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我们开始聊聊如何将我们的服务端和微信公众平台对接!(一)接入流程解析在我们的开发过程中无论如何最好的参考工具当然是...
    99+
    2023-05-31
    java 微信公众平台
  • Vue如何开发Html5微信公众号
    这篇文章主要介绍了Vue如何开发Html5微信公众号,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、调起微信支付在微信浏览器里面打开H5网...
    99+
    2024-04-02
  • Java 微信公众号开发相关总结
    目录首先必须要有一个个人微信公众号效果图后台路由代码完整代码首先必须要有一个个人微信公众号 个人微信公众号相关的接口权限有限,不过用于个人学习体验一下足够了,如图: 然后进入微信...
    99+
    2024-04-02
  • 如何使用Java开发微信公众号
    这篇文章给大家介绍如何使用Java开发微信公众号,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。首先必须要有一个个人微信公众号个人微信公众号相关的接口权限有限,不过用于个人学习体验一下足够了,如图:然后进入微信公众后台,...
    99+
    2023-06-15
  • PHP微信公众号开发函数大揭秘:curl、xml、sha1等函数的微信公众号开发指南
    PHP微信公众号开发函数大揭秘:curl、xml、sha1等函数的微信公众号开发指南导语:微信公众号已经成为了很多企业进行推广、营销以及与用户互动的重要平台,而PHP作为一种广泛应用的开发语言,在微信公众号开发中也有其独特的优势。本文将为大...
    99+
    2023-11-18
    微信 PHP 开发函数
  • 微信小程序 | 微信公众平台SpringBoot开发实例 │ 开发一个简易的个人微信公众号
     开发一个简易的个人微信公众号,并演示对不同相对地址的整合方法、JSON数据的处理方法(处理后以HTML文件显示)。 1、应用开发 1●创建类InitMenu 在包edu.bookcode中创建caseex子包,并在包edu.boo...
    99+
    2023-08-31
    微信公众平台 spring boot java 微信
  • nodejs中怎么实现微信公众号开发
    今天就跟大家聊聊有关nodejs中怎么实现微信公众号开发,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1.公众平台测试帐号的使用登录微信公众平台,由...
    99+
    2024-04-02
  • C#微信公众号开发之消息处理
    前言: 回顾上一节服务器配置的内容,我们已经可以自己完成公众号服务器的配置。配置完成之后,我们就可以通过调用的方式,完成对消息管理的处理。当用户关注公众号或者发送消息的时候,我们应该...
    99+
    2024-04-02
  • PHP中如何进行微信公众号开发?
    随着移动互联网的发展和普及,微信已成为一个重要的社交平台和移动应用程序。因此,许多企业和组织都开始利用微信公众号来推广自己的产品和服务。而PHP语言是一种广泛应用于Web开发的编程语言,因此在PHP中进行微信公众号开发也是一种常见的选择。本...
    99+
    2023-05-14
    PHP 微信公众号 开发
  • C#微信公众号开发之用户管理
    前言: 微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同时,微信公众号提供了相应的接口方便我们调用,可方便的把用户同步到...
    99+
    2024-04-02
  • 微信公众号开发消息推送功能
    目录微信公众号开发微信公众号简介注册微信公众号注册测试公众号搭建微信本地调试环境微信公众号接入(校验签名)给指定用户推送消息网页授权获取用户openid给指定用户发送模板信息微信公众...
    99+
    2023-02-15
    微信公众号开发消息推送 微信公众号开发
  • 如何在PHP中实现微信公众号开发
    随着移动互联网的发展,微信成为了一个非常受欢迎的社交媒体平台。越来越多的企业和个人开始将微信作为推广和用户互动的渠道。为了在微信平台上搭建自己的公众号,开发一款具有吸引力的应用程序是必不可少的。而对于PHP开发者来说,如何在PHP中实现微信...
    99+
    2023-05-20
    PHP 实现 微信公众号开发
  • 如何在微信公众号上进行PHP开发
    如何在微信公众号上进行PHP开发微信公众号已经成为了一个非常受欢迎的社交平台,许多企业和个人都希望能够在微信公众号上进行开发,以吸引更多的用户和粉丝。PHP作为一种广泛使用的后端编程语言,也可以应用于微信公众号的开发中。本文将介绍如何使用P...
    99+
    2023-10-27
    指南 微信公众号 PHP开发
  • C#微信公众号开发之自定义菜单
    前言: 回顾之前的微信公众号配置和消息处理的内容,我们已经掌握了如何配置服务器与微信公众号建立连接,也掌握了通过消息管理的方式,对用户的信息进行处理,完成公众号消息回复功能,实现公众...
    99+
    2024-04-02
  • C#微信公众号开发之服务器配置
    前言: 如果让大家说出一款国内比较热门的社交软件,那无疑就是QQ和微信了,说到微信,无不例外的会想到微信公众号和小程序,所以现在它们已经是很多企业流量及品牌推广的主要途径, 而作为一...
    99+
    2024-04-02
  • 微信公众号发送模板消息
    一、登录微信公众号后台,开通模板消息功能,选择使用的模板消息或者申请新的模板消息,只有通过企业认证才能使用模板消息 模板消息申请下来后,保存模板消息Id,后续发送模板消息使用      二、接口权限 => 网页服务 => 网页授权 =...
    99+
    2023-09-05
    微信 服务器 运维 微信公众平台
  • 微信公众号添加zip
    微信公众号添加zip的教程...
    99+
    2024-04-02
  • PHP微信开发:如何实现多公众号管理
    随着微信公众号市场的日益火热,越来越多的企业和个人开始关注微信公众号开发,尤其是PHP微信开发技术。但是,对于需要同时管理多个公众号的人来说,如何实现多公众号的管理,是一个需要解决的问题。本文将介绍PHP微信开发中,如何实现多公众号管理。一...
    99+
    2023-05-14
    PHP 微信开发 多公众号管理
  • Vue微信公众号开发踩坑的示例分析
    这篇文章将为大家详细讲解有关Vue微信公众号开发踩坑的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。需求微信授权登录(基于公众号的登录方案)接入JS-SDK实现图...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作