请问这种免费微信商城系统认证系统怎么实现?(技术层面上)?

WiFi认证中、微信一键上网是怎么实现的? - OPENWRT专版 -
恩山无线论坛 -
Powered by Discuz!
后使用快捷导航没有帐号?
只需一步,快速开始
请完成以下验证码
请完成以下验证码
查看: 4120|回复: 5
WiFi认证中、微信一键上网是怎么实现的?
各位大神?我看有的WiFi认证中带有微信认证功能,其带有所谓的一键上网功能。就是点击一个图片(应该是有连接地址的)然后就可以上网了!想问下这个功能是怎么实现的呢?谢谢~
我的恩山、我的无线
The best wifi forum is right here.
额,只看,没有说额- -,别沉~
我的恩山、我的无线
The best wifi forum is right here.
谢谢帮顶哈&
我的恩山、我的无线
The best wifi forum is right here.
参考 twitter 认证
嗯!您这个也算属于一种密码验证吧?!twitter可能开放了一键关注功能。我在看微信中,发过来一个连接,然后点击连接就可以上网了!0 0!使用wifidog实现的。不知道 scola3有思路没&
我的恩山、我的无线
The best wifi forum is right here.
参考 twitter 认证 https://github.com/scola/twittrouter
嗯!您这个也算属于一种密码验证吧?!twitter可能开放了一键关注功能。我在看微信中,发过来一个连接,然后点击连接就可以上网了!0 0!使用wifidog实现的。不知道 scola3有思路没
我的恩山、我的无线
The best wifi forum is right here.
谢谢帮顶哈
我的恩山、我的无线
The best wifi forum is right here.
Powered by查看: 8984|回复: 61
【大合集】微信公众平台开发教程
阅读权限255
在线时间 小时
阅读权限255
在线时间 小时
(九)微信公众平台通用开发框架
开发了几个微信项目,一直在思考:
如何将微信相关的处理与业务系统联系在一起?
如何做到彼此分离,且易于扩展?
能否开发一套独立的微信服务框架,支持各种业务应用?
二、现有常用的服务框架
支持多种业务应用,我们通过分层的方式来实现。将复杂的系统进行分层,将一些功能或者特有的逻辑进行封装,封装为不同的基础服务或中间件。业务层无需关心底层具体实现,只需进行简单调用、组装,即可支撑强大的业务应用。这样保证了层级独立,也使得系统易于维护和扩展。在一个平台基础上,可以构建多种业务应用。就像建楼房,地基打好了,楼房样式可以多种多样。也好比做菜,各种食材准备好了,可以进行不同搭配组合,就能做出不同的美味。常用的框架结构:MVC、MVVM等。以下就是通常的MVC架构。
91.jpg (0 Bytes, 下载次数: 1)
15:07 上传
三、微信服务框架
但是微信公众平台与以往的项目有所不同。其实现不再基于计算机底层实现。从应用层面讲,需要对业务的上层,即显示层和前端逻辑层、通信层,进行封装,下面才是真正的业务系统。从整体考虑,系统通过设计通用微信服务框架,支持所有业务。微信服务框架的改动,只与微信接口的调整做相关。多个业务系统,公用一套微信服务框架。这里介绍一种实现架构,如有欠缺,欢迎批评指正。
1、由微信服务框架,负责与微信服务器进行交互,包括验证签名、消息处理、消息分发、安全策略、日志处理等。
2、通过服务接口,将微信服务框架与业务逻辑进行分离,通过服务注册,将业务服务注册到微信服务框架。
3、通过微信服务框架的服务分发器,调用具体的业务应用。
4、业务应用,可以全新开发,也可以在已有的业务逻辑基础上,封装相关服务,并提供对应Provider,对微信接口予以支持。
具体框架图如下所示:
92.jpg (0 Bytes, 下载次数: 1)
15:07 上传
四、未来信息系统实现的一些愚见
仅仅是个人的一些看法。
从一个业务系统长远发展来看,一套业务系统,UI端会很多。特别是移动互联网的发展,许多功能需要移动化,之前的PC端、Web端,已经有一点的局限。
还有云计算的发展和深入,我们的业务服务也可以部署在云端。这些都对传统的信息系统提出了挑战。
如何将业务系统与前端展现相分离?
如何支持多终端?
能否实现一套业务逻辑,多端展现?
无论是开发新系统新应用,还是在已有的系统上扩展,这些问题必须认真考虑。业务逻辑需要更加细化、更加独立,业务逻辑需要从前端抽取出来,为了适应各种终端应用,可能需要加入一些适配层、代理层。尽管难度很大,但是在这个信息化高速发展的时期,如果不顺应潮流,势必被时代所淘汰。所以,变革不可避免。未来信息系统开发框架可能会变为下图所示。这里只是一个简单提纲,以后会就这一点进行专题介绍。
93.jpg (0 Bytes, 下载次数: 2)
15:07 上传
阅读权限255
在线时间 小时
(十) 订阅号与服务号的区别
为了消除大家对订阅号与服务号的疑问,特总结如下:
101.jpg (0 Bytes, 下载次数: 7)
15:16 上传
高级接口:
102.jpg (0 Bytes, 下载次数: 0)
15:16 上传
订阅号功能(未认证):
103.jpg (0 Bytes, 下载次数: 1)
15:16 上传
认证后的服务号具有的功能:
104.jpg (0 Bytes, 下载次数: 0)
15:16 上传
详细的接口文档说明:
订阅号微信认证说明:
阅读权限255
在线时间 小时
本帖最后由 老头不过年 于
14:29 编辑
(一)微信公众账号注册流程
具体的操作步骤
1、注册公众账号
注册地址:
1)首先需要邮箱注册:
1.jpg (0 Bytes, 下载次数: 6)
14:15 上传
2)邮箱激活。邮箱将会收到激活邮件,点击激活链接即可。
3)需要登记个人信息。这里需要提供一些个人信息或者单位信息。
现在个人只允许注册订阅号,公司单位才能注册服务号,服务号比订阅号,功能更多,可以实现自定义菜单。
需要提供的信息,主要有身份证号码、本人手持身份证的照片,如果是单位注册,还需要单位注册号、营业执照及法人身份证及照片,感觉这个比较变态。哪个老总愿意让你给他和他的身份证合张影呢?
同一个手机号或同一个身份证号只允许注册两个微信公众平台账号。
个人信息登记:
2.jpg (0 Bytes, 下载次数: 3)
14:16 上传
企业用户上面的个人信息也要填写的,只是运营者的个人信息。
3.jpg (0 Bytes, 下载次数: 2)
14:16 上传
4.jpg (0 Bytes, 下载次数: 0)
14:16 上传
4)输入公众账号相关信息了。
在输入公众号的名称和描述时要注意,公众账号的名称是不能编辑的,一旦提交,再不能改,一定要慎重。
注册需要7天内审核。具体的注册步骤这里不再赘述。
5.jpg (0 Bytes, 下载次数: 1)
14:16 上传
2、完善资料
如果审核通过,可以进行下一步的工作了。如何将我们的服务绑定到公众账号呢?
主要是上传头像,也可以修改描述信息。不过注意,一个月只能修改一次。 所以,在做一个新的应用时,一定要等到,需求已定,UE也设计好了图标再处理。
如有修改,只能等一个月了。
3、成为开发者:
首先关闭编辑模式,开启开发模式
6.jpg (0 Bytes, 下载次数: 0)
14:16 上传
这里真正可以绑定我们自己的服务器了。
7.jpg (0 Bytes, 下载次数: 0)
14:16 上传
绑定服务地址和token,服务器地址必须是公网IP,其端口要使用80
token值尽量复杂一点,一旦被人破解,很可能被人利用。
因为,在初次访问服务器的时候,需要一次身份验证,这时需要token。而且一经验证成功,今后不再验证。
公众平台消息接口为开发者提供了一种新的消息处理方式。
阅读权限255
在线时间 小时
本帖最后由 老头不过年 于
14:30 编辑
(二) 基本原理及消息接口
一、基本原理
在开始做之前,大家可能对这个很感兴趣,但是又比较茫然。是不是很复杂?很难学啊?
其实恰恰相反,很简单。为了打消大家的顾虑,先简单介绍了微信公众平台的基本原理。
微信服务器就相当于一个转发服务器,终端(手机、Pad等)发起请求至微信服务器,微信服务器,然后将请求转发给自定义服务(这就里就是我们的具体实现)。
服务处理完毕,然后挥发给微信服务器,微信服务器再将具体响应回复到终端。
通信协议为:HTTP
数据格式为:XML
具体的流程如下图所示:
21.jpg (0 Bytes, 下载次数: 6)
14:19 上传
其实,我们需要做的事情,就是对HTTP请求,做出响应。
具体的请求内容,我们按照特定的XML格式去解析,处理完毕后,也要按照特定的XML格式返回。
我们只需要一个简单的实现HttpHandler即可。
当然,微信平台还能实现更加复杂的业务,比如微信可以作为内嵌的浏览器,我们可以通过微信的链接,打开htm界面,然后实现自己的逻辑。
二、消息接口(官方文档)
申请消息接口
点击申请,填写网址url和token,其中token可由开发者可以任意填写,用作生成签名。
22.jpg (0 Bytes, 下载次数: 6)
14:19 上传
公众平台用户提交信息后,微信服务器将发送GET请求到填写的URL上,并且带上四个参数:
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,否则接入失败。
signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
加密/校验流程:
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
当普通微信用户向公众账号发消息时,微信服务器将POST该消息到填写的URL上。结构如下:
文本消息 &xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[text]]&&/MsgType&
&Content&&![CDATA[this is a test]]&&/Content&
&MsgId&3456&/MsgId&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 开发者微信号
FromUserName& & & & 发送方帐号(一个OpenID)
CreateTime& & & & 消息创建时间 (整型)
MsgType& & & & text
Content& & & & 文本消息内容
MsgId& & & & 消息id,64位整型
图片消息 &xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[image]]&&/MsgType&
&PicUrl&&![CDATA[this is a url]]&&/PicUrl&
&MsgId&3456&/MsgId&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 开发者微信号
FromUserName& & & & 发送方帐号(一个OpenID)
CreateTime& & & & 消息创建时间 (整型)
MsgType& & & & image
PicUrl& & & & 图片链接
MsgId& & & & 消息id,64位整型
地理位置消息&xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[location]]&&/MsgType&
&Location_X&23.134521&/Location_X&
&Location_Y&113.358803&/Location_Y&
&Scale&20&/Scale&
&Label&&![CDATA[位置信息]]&&/Label&
&MsgId&3456&/MsgId&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 开发者微信号
FromUserName& & & & 发送方帐号(一个OpenID)
CreateTime& & & & 消息创建时间 (整型)
MsgType& & & & location
Location_X& & & & 地理位置纬度
Location_Y& & & & 地理位置经度
Scale& & & & 地图缩放大小
Label& & & & 地理位置信息
MsgId& & & & 消息id,64位整型
链接消息&xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[link]]&&/MsgType&
&Title&&![CDATA[公众平台官网链接]]&&/Title&
&Description&&![CDATA[公众平台官网链接]]&&/Description&
&Url&&![CDATA[url]]&&/Url&
&MsgId&3456&/MsgId&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 接收方微信号
FromUserName& & & & 发送方微信号,若为普通用户,则是一个OpenID
CreateTime& & & & 消息创建时间
MsgType& & & & 消息类型,link
Title& & & & 消息标题
Description& & & & 消息描述
Url& & & & 消息链接
MsgId& & & & 消息id,64位整型
事件推送只支持微信4.5版本,目前开启自定义菜单接口事件推送、关注与取消关注事件推送。其余功能即将开放,敬请期待。&xml&&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[FromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[event]]&&/MsgType&
&Event&&![CDATA[EVENT]]&&/Event&
&EventKey&&![CDATA[EVENTKEY]]&&/EventKey&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 接收方微信号
FromUserName& & & & 发送方微信号,若为普通用户,则是一个OpenID
CreateTime& & & & 消息创建时间
MsgType& & & & 消息类型,event
Event& & & & 事件类型,subscribe(订阅)、unsubscribe(取消订阅)、CLICK(自定义菜单点击事件)
EventKey& & & & 事件KEY值,与自定义菜单接口中KEY值对应
对于每一个POST请求,开发者在响应包中返回特定xml结构,对该消息进行响应(现支持回复文本、图文、语音、视频、音乐)。
微信服务器在五秒内收不到响应会断掉连接。
回复xml结构如下:
回复文本消息 &xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[text]]&&/MsgType&
&Content&&![CDATA[content]]&&/Content&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 接收方帐号(收到的OpenID)
FromUserName& & & & 开发者微信号
CreateTime& & & & 消息创建时间
MsgType& & & & text
Content& & & & 回复的消息内容,长度不超过2048字节
回复音乐消息 &xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[music]]&&/MsgType&
&Title&&![CDATA[TITLE]]&&/Title&
&Description&&![CDATA[DESCRIPTION]]&&/Description&
&MusicUrl&&![CDATA[MUSIC_Url]]&&/MusicUrl&
&HQMusicUrl&&![CDATA[HQ_MUSIC_Url]]&&/HQMusicUrl&
&/xml&复制代码参数& & & & 描述
ToUserName& & & & 接收方帐号(收到的OpenID)
FromUserName& & & & 开发者微信号
CreateTime& & & & 消息创建时间
MsgType& & & & music
MusicUrl& & & & 音乐链接
HQMusicUrl& & & & 高质量音乐链接,WIFI环境优先使用该链接播放音乐
回复图文消息&xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[fromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[news]]&&/MsgType&
&ArticleCount&2&/ArticleCount&
&Articles&
&Title&&![CDATA[title1]]&&/Title&
&Description&&![CDATA[description1]]&&/Description&
&PicUrl&&![CDATA[picurl]]&&/PicUrl&
&Url&&![CDATA[url]]&&/Url&
&Title&&![CDATA[title]]&&/Title&
&Description&&![CDATA[description]]&&/Description&
&PicUrl&&![CDATA[picurl]]&&/PicUrl&
&Url&&![CDATA[url]]&&/Url&
&/Articles&
&/xml& 复制代码参数& & & & 描述
ToUserName& & & & 接收方帐号(收到的OpenID)
FromUserName& & & & 开发者微信号
CreateTime& & & & 消息创建时间
MsgType& & & & news
ArticleCount& & & & 图文消息个数,限制为10条以内
Articles& & & & 多条图文消息信息,默认第一个item为大图
Title& & & & 图文消息标题
Description& & & & 图文消息描述
PicUrl& & & & 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80。
Url& & & & 点击图文消息跳转链接
官方接口文档:
1.用户OpenID对一个公众号是固定唯一的串
2.请使用80端口
尽请关注:后续我们将全面讲解具体的开发过程。
三、消息类图
23.jpg (0 Bytes, 下载次数: 4)
14:19 上传
阅读权限255
在线时间 小时
(三) 基础框架搭建
上一章,我们已经初步讲解了微信公众账号开发的基本原理,今天我们来探索设计实现。
首先我们设计了模块层次图,当然图中只是给出一种实现方式,不局限于此。具体见下图。
主要功能介绍如下:
1)请求接口层。处理HTTP请求,及响应
2)分发层。由接口层传入请求,然后具体分析请求类型,分发至不同的处理器
3)业务逻辑层。这里是我们的具体业务逻辑了,根据请求,实现具体的业务逻辑。
4)数据层。我们在实现某个应用时可能需要访问数据,可以是数据库或者是文件。如果是简单应用,可能没有这一层。
其实,具体的应用可以在这个结构上去扩展,可以扩展消息对象层、业务对象层、数据访问层、功能管理层等。这里只是提供一种思路,不局限于此。
31.jpg (0 Bytes, 下载次数: 4)
14:34 上传
根据层次图,设计流程图,具体讲述实现的各个过程。以便了解整个处理过程。如下图所示:
32.jpg (0 Bytes, 下载次数: 2)
14:34 上传
根据流程图,我们能够清晰的了解整个流程,消息处理的具体实现步骤。
下面我们针对每个流程进行代码实现。
一、接收HTTP请求
我们需要一个HttpHandler或者一个网页,来处理微信服务端HTTP请求。
这里我们使用了HttpHandler。因为其灵活性高,性能好。
具体实现如下。& &public class WeiXinHttpHandler:IHttpHandler
& & {
& && &&&/// &summary&
& && &&&///
& && &&&/// &/summary&
& && &&&public bool IsReusable
& && &&&{
& && && && &get { }
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理请求
& && &&&/// &/summary&
& && &&&/// &param name=&context&&&/param&
& && &&&public void ProcessRequest(HttpContext context)
& && &&&{
& && && && &//由微信服务接收请求,具体处理请求
& && && && &WeiXinService wxService = new WeiXinService(context.Request);
& && && && &string responseMsg = wxService.Response();
& && && && &context.Response.Clear();
& && && && &context.Response.Charset = &UTF-8&;
& && && && &context.Response.Write(responseMsg);
& && && && &context.Response.End();
& && &&&}
& & }复制代码如果是HTTPHandler,需要在配置文件中,配置具体的应用。具体的节点配置,我们不作说明。直接给出例子,配置HttpHandler节点如下&httpHandlers&
& &&add verb=&*& path=&WXService.ashx& type=&namespace.WeiXinHttpHandler,WXWeb& validate=&true&/&
&/httpHandlers&复制代码二、分发请求
为了能功能封装,我们也将此封装在了处理组件中。其实可以放置在HttpHandler中的。
1)验证签名
如果是首次请求,需要验证签名。就相当于一次HTTP握手。之前在上一章中,设置的服务器URL以及token值,这个功能就是检验是否链接成功。
这个请求是GET请求。以下具体说明(官方):
业务逻辑:
加密/校验流程:
&1& 将token、timestamp、nonce三个参数进行字典序排序
&2& 将三个参数字符串拼接成一个字符串进行SHA1加密
&3& 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
而官方只提供了PHP的代码示例,很多东西在C#中并非直译既得。所以这里面也有一些具体处理。先看官方的代码:& & private function checkSignature()
& & {
& && &&&$signature = $_GET[&signature&];
& && &&&$timestamp = $_GET[&timestamp&];
& && &&&$nonce = $_GET[&nonce&];& &
& && && && && &
& && &&&$token = TOKEN;
& && &&&$tmpArr = array($token, $timestamp, $nonce);
& && &&&sort($tmpArr);
& && &&&$tmpStr = implode( $tmpArr );
& && &&&$tmpStr = sha1( $tmpStr );
& && &&&
& && &&&if( $tmpStr == $signature ){
& && && && &
& && &&&}else{
& && && && &
& && &&&}
& & }复制代码我们将其翻译成C#版本:
& && &&&/// &summary&
& && &&&/// 检查签名
& && &&&/// &/summary&
& && &&&/// &param name=&request&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private bool CheckSignature()
& && &&&{
& && && && &string signature = Request.QueryString[SIGNATURE];
& && && && &string timestamp = Request.QueryString[TIMESTAMP];
& && && && &string nonce = Request.QueryString[NONCE];
& && && && &List&string& list = new List&string&();
& && && && &list.Add(TOKEN);
& && && && &list.Add(timestamp);
& && && && &list.Add(nonce);
& && && && &//排序
& && && && &list.Sort();
& && && && &//拼串
& && && && &string input = string.E
& && && && &foreach (var item in list)
& && && && &{
& && && && && & input +=
& && && && &}
& && && && &//加密
& && && && &string new_signature = SecurityUtility.SHA1Encrypt(input);
& && && && &//验证
& && && && &if (new_signature == signature)
& && && && &{
& && && && && &
& && && && &}
& && && && &else
& && && && &{
& && && && && &
& && && && &}
& && &&&}复制代码这里需要SHA1加密,具体的算法如下:& && &&&/// &summary&
& && &&&/// SHA1加密
& && &&&/// &/summary&
& && &&&/// &param name=&intput&&输入字符串&/param&
& && &&&/// &returns&加密后的字符串&/returns&
& && &&&public static string SHA1Encrypt(string intput)
& && &&&{
& && && && &byte[] StrRes = Encoding.Default.GetBytes(intput);
& && && && &HashAlgorithm mySHA = new SHA1CryptoServiceProvider();
& && && && &StrRes = mySHA.ComputeHash(StrRes);
& && && && &StringBuilder EnText = new StringBuilder();
& && && && &foreach (byte Byte in StrRes)
& && && && &{
& && && && && & EnText.AppendFormat(&{0:x2}&, Byte);
& && && && &}
& && && && &return EnText.ToString();
& && &&&}复制代码2)分发请求
接下来就是具体的消息请求了,这里都是POST请求。
因为有多种消息类型,我们通过工厂类来进行封装,然后每种消息都有专门的处理器来进行处理。具体实现逻辑:& && &&&/// &summary&
& && &&&/// 处理请求
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&private string ResponseMsg()
& && &&&{
& && && && &string requestXml = Common.ReadRequest(this.Request);
& && && && &IHandler handler = HandlerFactory.CreateHandler(requestXml);
& && && && &if (handler != null)
& && && && &{
& && && && && & return handler.HandleRequest();
& && && && &}
& && && && &return string.E
& && &&&}复制代码处理请求的对外方法(HttpHandler调用的方法就是这个了),即:& && &&&/// &summary&
& && &&&/// 处理请求,产生响应
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string Response()
& && &&&{
& && && && &string method = Request.HttpMethod.ToUpper();
& && && && &//验证签名
& && && && &if (method == &GET&)
& && && && &{
& && && && && & if (CheckSignature())
& && && && && & {
& && && && && && &&&return Request.QueryString[ECHOSTR];
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&return &error&;
& && && && && & }
& && && && &}
& && && && &//处理消息
& && && && &if (method == &POST&)
& && && && &{
& && && && && & return ResponseMsg();
& && && && &}
& && && && &else
& && && && &{
& && && && && & return &无法处理&;
& && && && &}
& && &&&}复制代码三、消息处理器具体处理消息
1)消息类型
首先我们来看下,具体的消息类型,其实上一张中已经明确给了消息的接口。
这里再看具体看一下,请求的消息类型有哪些,回复的消息类型有哪些等。
千万要注意,请求的消息是文本类型,回复的消息,不一定也是文本哦,可以是图文、音乐等任意一种可回复的消息。具体见下表所示。
33.jpg (0 Bytes, 下载次数: 1)
14:34 上传
2)根据具体的消息接口,设计消息类。
这里给出类图,供参考。
34.jpg (0 Bytes, 下载次数: 5)
14:34 上传
3)针对不同的消息,会有不同的处理器,来看下具体的类图。
35.jpg (0 Bytes, 下载次数: 0)
14:34 上传
4)具体业务处理
每个handler里面就是可以处理具体请求。输入的什么消息,访问那些数据,调用服务等,都在这里处理。
还是建议大家对具体的业务进行单独封装,在Handler中,只提供调用的接口。
因为随着业务的增加,一个Handler可能要处理很多业务,如果所有的操作逻辑都写在这里,势必影响阅读,也不易于维护与扩展。
5)产生回复消息
在处理完请求后,需要生成回复消息,响应到终端。消息格式,就是我们介绍那些消息类型,但必须是可用于回复的,当前支持的有:文本、图文、音乐等。
一定要明确:回复的消息类型不一定要与请求的消息类型一样,比如,请求是文本,回复的可以是图文、音乐。
产生回复消息的过程,其实,就是特定的消息对象格式化为对应的XML的过程,然后将XML响应至微信服务器。
这里以微信用户关注公众账号,然后服务端处理处理事件请求,登记用户,并提示欢迎信息。& & class EventHandler : IHandler
& & {
& && &&&/// &summary&
& && &&&/// 请求的xml
& && &&&/// &/summary&
& && &&&private string RequestXml { }
& && &&&/// &summary&
& && &&&/// 构造函数
& && &&&/// &/summary&
& && &&&/// &param name=&requestXml&&&/param&
& && &&&public EventHandler(string requestXml)
& && &&&{
& && && && &this.RequestXml = requestX
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理请求
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string HandleRequest()
& && &&&{
& && && && &string response = string.E
& && && && &EventMessage em = EventMessage.LoadFromXml(RequestXml);
& && && && &if (em.Event == EventType.Subscribe)
& && && && &{
& && && && && & //注册用户
& && && && && & User user = new User();
& && && && && & user.OpenID = em.FromUserN
& && && && && & UserManager.Regester(user);
& && && && && & //回复欢迎消息
& && && && && & TextMessage tm = new TextMessage();
& && && && && & tm.ToUserName = em.FromUserN
& && && && && & tm.FromUserName = em.ToUserN
& && && && && & tm.CreateTime = Common.GetNowTime();
& && && && && & tm.Content = &欢迎您关注xxx,我是小微。有什么我能帮助您的吗?&;
& && && && && & response = tm.GenerateContent();
& && && && &}
& && && && &
& && &&&}
& & }复制代码四、HTTP响应
最后将处理结果返回至最初HttpHandler,响应给微信服务器,直接Response处理。这也是在最开始设计的HttpHandler中实现的。
下面是代码片段,具体可见一、Http请求& && && &&&context.Response.Clear();
& && && && &context.Response.Charset = &UTF-8&;
& && && && &context.Response.Write(responseMsg);
& && && && &context.Response.End();
阅读权限255
在线时间 小时
(四) 实例入门:机器人(附源码)
上一篇文章,写了基本框架,可能很多人会觉得晕头转向,这里提供一个简单的例子来予以说明,希望能帮你解开谜团。
一、功能介绍
通过微信公众平台实现在线客服机器人功能。主要的功能包括:简单对话、查询天气等服务。
这里只是提供比较简单的功能,重在通过此实例来说明公众平台的具体研发过程。只是一个简单DEMO,如果需要的话可以在此基础上进行扩展。
当然后续我们还会推出比较复杂的应用实例。
二、具体实现
1、提供访问接口
这里不再赘述,参照上一章,微信公众账号开发教程(二) 基础框架搭建
2、签名认证和分发请求
这里不再赘述,参照上一章,微信公众账号开发教程(二) 基础框架搭建
3、处理请求,并响应
当微信用户关注公众账号时,可以给其适当的提示。可以是欢迎词,可以是帮助提示。
直接上代码:& & class EventHandler : IHandler
& & {
& && &&&/// &summary&
& && &&&/// 请求的xml
& && &&&/// &/summary&
& && &&&private string RequestXml { }
& && &&&/// &summary&
& && &&&/// 构造函数
& && &&&/// &/summary&
& && &&&/// &param name=&requestXml&&&/param&
& && &&&public EventHandler(string requestXml)
& && &&&{
& && && && &this.RequestXml = requestX
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理请求
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string HandleRequest()
& && &&&{
& && && && &string response = string.E
& && && && &EventMessage em = EventMessage.LoadFromXml(RequestXml);
& && && && &if (em.Event.Equals(&subscribe&,StringComparison.OrdinalIgnoreCase))
& && && && &{
& && && && && & //回复欢迎消息
& && && && && & TextMessage tm = new TextMessage();
& && && && && & tm.ToUserName = em.FromUserN
& && && && && & tm.FromUserName = em.ToUserN
& && && && && & tm.CreateTime = Common.GetNowTime();
& && && && && & tm.Content = &欢迎您关注***,我是大哥大,有事就问我,呵呵!\n\n&;
& && && && && & response = tm.GenerateContent();
& && && && &}
& && && && &
& && &&&}
& & }复制代码2)问候
简单的交流问候,比如你好、帮助等等,跟我们使用微信聊天一样,不过回应是由我们的程序响应。具体功能,可以根据自己的需要进行添加。
微信本来就是沟通的平台。这个案例,可以用于在线服务机器人,类似于淘宝的客服机器人,可是我们这个是微信版的。呵呵
其实,很简单,获取请求消息,根据关键字来匹配回应。当然这里可能要做的工作很多,如何支持智能匹配,如何支持模糊匹配等。
代码如下:
& & /// &summary&
& & /// 文本信息处理类
& & /// &/summary&
& & public class TextHandler : IHandler
& & {
& && &&&/// &summary&
& && &&&/// 请求的XML
& && &&&/// &/summary&
& && &&&private string RequestXml { }
& && &&&/// &summary&
& && &&&/// 构造函数
& && &&&/// &/summary&
& && &&&/// &param name=&requestXml&&请求的xml&/param&
& && &&&public TextHandler(string requestXml)
& && &&&{
& && && && &this.RequestXml = requestX
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理请求
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string HandleRequest()
& && &&&{
& && && && &string response = string.E
& && && && &TextMessage tm = TextMessage.LoadFromXml(RequestXml);
& && && && &string content = tm.Content.Trim();
& && && && &if (string.IsNullOrEmpty(content))
& && && && &{
& && && && && & response = &您什么都没输入,没法帮您啊,%&_&%。&;
& && && && &}
& && && && &else
& && && && &{
& && && && && & if (content.StartsWith(&tq&, StringComparison.OrdinalIgnoreCase))
& && && && && & {
& && && && && && &&&string cityName = content.Substring(2).Trim();
& && && && && && &&&response = WeatherHelper.GetWeather(cityName);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&response = HandleOther(content);
& && && && && & }
& && && && &}
& && && && &tm.Content =
& && && && &//进行发送者、接收者转换
& && && && &string temp = tm.ToUserN
& && && && &tm.ToUserName = tm.FromUserN
& && && && &tm.FromUserName =
& && && && &response = tm.GenerateContent();
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理其他消息
& && &&&/// &/summary&
& && &&&/// &param name=&tm&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private string HandleOther(string requestContent)
& && &&&{
& && && && &string response = string.E
& && && && &if (requestContent.Contains(&你好&) || requestContent.Contains(&您好&))
& && && && &{
& && && && && & response = &您也好~&;
& && && && &}
& && && && &else if (requestContent.Contains(&傻&))
& && && && &{
& && && && && & response = &我不傻!哼~ &;
& && && && &}
& && && && &else if (requestContent.Contains(&逼&) || requestContent.Contains(&操&))
& && && && &{
& && && && && & response = &哼,你说脏话! &;
& && && && &}
& && && && &else if (requestContent.Contains(&是谁&))
& && && && &{
& && && && && & response = &我是大哥大,有什么能帮您的吗?~&;
& && && && &}
& && && && &else if (requestContent.Contains(&再见&))
& && && && &{
& && && && && & response = &再见!&;
& && && && &}
& && && && &else if (requestContent.Contains(&bye&))
& && && && &{
& && && && && & response = &Bye!&;
& && && && &}
& && && && &else if (requestContent.Contains(&谢谢&))
& && && && &{
& && && && && & response = &不客气!嘿嘿&;
& && && && &}
& && && && &else if (requestContent == &h& || requestContent == &H& || requestContent.Contains(&帮助&))
& && && && &{
& && && && && & response = @&查询天气,输入tq 城市名称\拼音\首字母&;
& && && && &}
& && && && &else
& && && && &{
& && && && && & response = &您说的,可惜,我没明白啊,试试其他关键字吧。&;
& && && && &}
& && && && &
& && &&&}
& & }
复制代码3)查询天气
这个功能需要请求实时查询的,请求官方的天气发布网站,然后解析其返回值,按照我们需要的格式,组织天气信息,最后发送给微信客户。
采用文本消息方式处理。
用户请求,只需输入:tq 城市名称/拼音/首字母,即可获取消息。
回复的消息:(以北京为例)
今天:(17℃~4℃)晴北风4-5级转3-4级4-5级转3-4级
24小时穿衣指数:天气冷,建议着棉服、羽绒服、皮夹克加羊毛衫等冬季服装。年老体弱者宜着厚棉衣、冬大衣或厚羽绒服。
明天:(14℃~3℃)晴转多云微风小于3级
48小时穿衣指数:天气冷,建议着棉服、羽绒服、皮夹克加羊毛衫等冬季服装。年老体弱者宜着厚棉衣、冬大衣或厚羽绒服。
来看源码吧:& & class WeatherHelper
& & {
& && &&&/// &summary&
& && &&&/// 城市集合字段
& && &&&/// &/summary&
& && &&&private static Dictionary&string, City& mC
& && &&&/// &summary&
& && &&&/// 城市集合
& && &&&/// &/summary&
& && &&&public static Dictionary&string, City& Cities
& && &&&{
& && && && &get
& && && && &{
& && && && && & if (mCities == null)
& && && && && & {
& && && && && && &&&LoadCities();
& && && && && & }
& && && && && & return mC
& && && && &}
& && &&&}
& && &&&/// &summary&
& && &&&/// 加载城市
& && &&&/// &/summary&
& && &&&private static void LoadCities()
& && &&&{
& && && && &mCities = new Dictionary&string, City&();
& && && && &mCities.Clear();
& && && && &mCities.Add(&&, new City() { Code = &&, Name = &北京&, PinYin = &beijing&, FristLetter = &bj& });
& && && && &mCities.Add(&&, new City() { Code = &&, Name = &上海&, PinYin = &shanghai&, FristLetter = &sh& });
& && && && &mCities.Add(&&, new City() { Code = &&, Name = &武汉&, PinYin = &wuhai&, FristLetter = &wh& });
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 获取城市的天气
& && &&&/// &/summary&
& && &&&/// &param name=&name&&城市名称、拼音或首字母&/param&
& && &&&/// &returns&&/returns&
& && &&&public static string GetWeather(string name)
& && &&&{
& && && && &string result = string.E
& && && && &string cityCode = string.E
& && && && &//获取城市编码
& && && && &IEnumerable&string& codes = from item in Cities
& && && && && && && && && && && && && & where item.Value != null
& && && && && && && && && && && && && && && & && (item.Value.Name.Equals(name, StringComparison.OrdinalIgnoreCase)
& && && && && && && && && && && && && && && && && & || item.Value.PinYin.Equals(name, StringComparison.OrdinalIgnoreCase)
& && && && && && && && && && && && && && && && && & || item.Value.FristLetter.Equals(name, StringComparison.OrdinalIgnoreCase))
& && && && && && && && && && && && && & select item.Value.C
& && && && &if (codes != null && codes.Count() & 0)
& && && && &{
& && && && && & cityCode = codes.First&string&();
& && && && &}
& && && && &//http请求,获取天气
& && && && &if (!string.IsNullOrEmpty(cityCode))
& && && && &{
& && && && && & string url = &http://m.weather.com.cn/data/{0}.html&;
& && && && && & url = string.Format(url, cityCode);
& && && && && & WebRequest request = HttpWebRequest.Create(url);
& && && && && & //超时时间为:2秒
& && && && && & request.Timeout = 2000;
& && && && && & request.Credentials = CredentialCache.DefaultC
& && && && && & WebResponse response = request.GetResponse();
& && && && && & StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
& && && && && & string weahterInfo = reader.ReadToEnd();
& && && && && & if (string.IsNullOrEmpty(weahterInfo))
& && && && && & {
& && && && && && &&&result = &暂时没有取到天气数据,请稍后再试&;
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&XmlDocument doc = JsonConvert.DeserializeXmlNode(weahterInfo);
& && && && && && &&&if (doc != null)
& && && && && && &&&{
& && && && && && && && &XmlNode node = doc.DocumentE
& && && && && && && && &if (node != null)
& && && && && && && && &{
& && && && && && && && && & StringBuilder builder = new StringBuilder();
& && && && && && && && && & builder.Append(node[&city&].InnerText).Append(&\n&);
& && && && && && && && && & builder.Append(node[&date_y&].InnerText).Append(& &).Append(node[&week&].InnerText).Append(&\n&);
& && && && && && && && && & builder.Append(&今天:&).Append(&(&).Append(node[&temp1&].InnerText).Append(&)&).Append(node[&weather1&].InnerText).Append(node[&wind1&].InnerText).Append(node[&fl1&].InnerText).Append(&\n&);
& && && && && && && && && & builder.Append(&24小时穿衣指数:&).Append(node[&index_d&].InnerText).Append(&\n&);
& && && && && && && && && & builder.Append(&明天:&).Append(&(&).Append(node[&temp2&].InnerText).Append(&)&).Append(node[&weather2&].InnerText).Append(node[&wind2&].InnerText).Append(node[&fl2&].InnerText).Append(&\n&);
& && && && && && && && && & builder.Append(&48小时穿衣指数:&).Append(node[&index48_d&].InnerText).Append(&\n&);
& && && && && && && && && & result = builder.ToString();
& && && && && && && && &}
& && && && && && &&&}
& && && && && && &&&#region 天气json数据格式
& && && && && && &&&/*
& && && && && &&&
& && && && && & {
& &&weatherinfo&: {
& && & &city&: &北京&,
& && & &city_en&: &beijing&,
& && & &date_y&: &日&,
& && & &date&: &&,
& && & &week&: &星期一&,
& && & &fchh&: &11&,
& && & &cityid&: &&,
& && & &temp1&: &17℃~5℃&,
& && & &temp2&: &16℃~5℃&,
& && & &temp3&: &18℃~4℃&,
& && & &temp4&: &17℃~5℃&,
& && & &temp5&: &14℃~6℃&,
& && & &temp6&: &14℃~2℃&,
& && & &tempF1&: &62.6℉~41℉&,
& && & &tempF2&: &60.8℉~41℉&,
& && & &tempF3&: &64.4℉~39.2℉&,
& && & &tempF4&: &62.6℉~41℉&,
& && & &tempF5&: &57.2℉~42.8℉&,
& && & &tempF6&: &57.2℉~35.6℉&,
& && & &weather1&: &晴转多云&,
& && & &weather2&: &多云&,
& && & &weather3&: &多云转晴&,
& && & &weather4&: &晴转多云&,
& && & &weather5&: &多云转阴&,
& && & &weather6&: &阴转晴&,
& && & &img1&: &0&,
& && & &img2&: &1&,
& && & &img3&: &1&,
& && & &img4&: &99&,
& && & &img5&: &1&,
& && & &img6&: &0&,
& && & &img7&: &0&,
& && & &img8&: &1&,
& && & &img9&: &1&,
& && & &img10&: &2&,
& && & &img11&: &2&,
& && & &img12&: &0&,
& && & &img_single&: &0&,
& && & &img_title1&: &晴&,
& && & &img_title2&: &多云&,
& && & &img_title3&: &多云&,
& && & &img_title4&: &多云&,
& && & &img_title5&: &多云&,
& && & &img_title6&: &晴&,
& && & &img_title7&: &晴&,
& && & &img_title8&: &多云&,
& && & &img_title9&: &多云&,
& && & &img_title10&: &阴&,
& && & &img_title11&: &阴&,
& && & &img_title12&: &晴&,
& && & &img_title_single&: &晴&,
& && & &wind1&: &微风&,
& && & &wind2&: &微风&,
& && & &wind3&: &微风&,
& && & &wind4&: &微风&,
& && & &wind5&: &微风&,
& && & &wind6&: &北风4-5级&,
& && & &fx1&: &微风&,
& && & &fx2&: &微风&,
& && & &fl1&: &小于3级&,
& && & &fl2&: &小于3级&,
& && & &fl3&: &小于3级&,
& && & &fl4&: &小于3级&,
& && & &fl5&: &小于3级&,
& && & &fl6&: &4-5级&,
& && & &index&: &较冷&,
& && & &index_d&: &建议着大衣、呢外套加毛衣、卫衣等服装。体弱者宜着厚外套、厚毛衣。因昼夜温差较大,注意增减衣服。&,
& && & &index48&: &冷&,
& && & &index48_d&: &天气冷,建议着棉服、羽绒服、皮夹克加羊毛衫等冬季服装。年老体弱者宜着厚棉衣、冬大衣或厚羽绒服。&,
& && & &index_uv&: &中等&,
& && & &index48_uv&: &弱&,
& && & &index_xc&: &适宜&,
& && & &index_tr&: &适宜&,
& && & &index_co&: &舒适&,
& && & &st1&: &17&,
& && & &st2&: &5&,
& && & &st3&: &17&,
& && & &st4&: &5&,
& && & &st5&: &18&,
& && & &st6&: &6&,
& && & &index_cl&: &适宜&,
& && & &index_ls&: &适宜&,
& && & &index_ag&: &极不易发&
& &}
}
& && && && && & */
& && && && && && &&&#endregion
& && && && && & }
& && && && &}
& && && && &else
& && && && &{
& && && && && & result = &没有获取到该城市的天气,请确定输入了正确的城市名称,如\'北京\'或者\'beijing\'或者\'bj\'&;
& && && && &}
& && && && &//返回
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 内部类:城市
& && &&&/// &/summary&
& && &&&internal class City
& && &&&{
& && && && &/// &summary&
& && && && &/// 编码
& && && && &/// &/summary&
& && && && &public string Code { }
& && && && &/// &summary&
& && && && &/// 名称
& && && && &/// &/summary&
& && && && &public string Name { }
& && && && &/// &summary&
& && && && &/// 拼音
& && && && &/// &/summary&
& && && && &public string PinYin { }
& && && && &/// &summary&
& && && && &/// 拼音首字母
& && && && &/// &/summary&
& && && && &public string FristLetter { }
& && &&&}
& & }
阅读权限255
在线时间 小时
(五)自定义菜单
一、概述:
如果只有输入框,可能太简单,感觉像命令行。自定义菜单,给我们提供了很大的灵活性,更符合用户的操作习惯。在一个小小的微信对话页面,可以实现更多的功能。菜单直观明了,不仅能提供事件响应,还支持URL跳转,如果需要的功能比较复杂,我们大可以使用URL跳转,跳转至我们的网页即可。
注意:自定义菜单,只有服务号才有此功能
如何注册,见第一章:微信公众账号开发教程(一) 基本原理及微信公众账号注册
效果如下,
51.jpg (0 Bytes, 下载次数: 1)
14:50 上传
接着我们详细介绍,如何实现自定义菜单?
二、详细步骤:
1、首先获取access_token
access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。
公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在开发模式中获得(需要已经成为开发者,且帐号没有异常状态)。注意调用所有微信接口时均需使用https协议。
接口调用请求说明
http请求方式: GET
参数& & & & 是否必须& & & & 说明
grant_type& & & & 是& & & & 获取access_token填写client_credential
appid& & & & 是& & & & 第三方用户唯一凭证
secret& & & & 是& & & & 第三方用户唯一凭证密钥,既appsecret
正常情况下,微信会返回下述JSON数据包给公众号:
{&access_token&:&ACCESS_TOKEN&,&expires_in&:7200}
参数& & & & 说明
access_token& & & & 获取到的凭证
expires_in& & & & 凭证有效时间,单位:秒
错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):
{&errcode&:40013,&errmsg&:&invalid appid&}
2、创建自定义菜单
自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。开启自定义菜单后,公众号界面如图所示:
目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
目前自定义菜单接口可实现两种类型按钮,如下:
用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event& & & & 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值& & & & (即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息。
接口调用请求说明
http请求方式:POST(请使用https协议)
请求示例 {
& &&&&button&:[
& &&&{& &
& && && & &type&:&click&,
& && && & &name&:&今日歌曲&,
& && && & &key&:&V1001_TODAY_MUSIC&
& && &},
& && &{
& && && &&&&type&:&click&,
& && && &&&&name&:&歌手简介&,
& && && &&&&key&:&V1001_TODAY_SINGER&
& && &},
& && &{
& && && &&&&name&:&菜单&,
& && && &&&&sub_button&:[
& && && &&&{& &
& && && && && &&type&:&view&,
& && && && && &&name&:&搜索&,
& && && && && &&url&:&http://www.soso.com/&
& && && && &},
& && && && &{
& && && && && &&type&:&view&,
& && && && && &&name&:&视频&,
& && && && && &&url&:&http://v.qq.com/&
& && && && &},
& && && && &{
& && && && && &&type&:&click&,
& && && && && &&name&:&赞一下我们&,
& && && && && &&key&:&V1001_GOOD&
& && && && &}]
& && & }]
复制代码参数说明
参数& & & & 是否必须& & & & 说明
button& & & & 是& & & & 一级菜单数组,个数应为1~3个
sub_button& & & & 否& & & & 二级菜单数组,个数应为1~5个
type& & & & 是& & & & 菜单的响应动作类型,目前有click、view两种类型
name& & & & 是& & & & 菜单标题,不超过16个字节,子菜单不超过40个字节
key& & & & click类型必须& & & & 菜单KEY值,用于消息接口推送,不超过128字节
url& & & & view类型必须& & & & 网页链接,用户点击菜单可打开链接,不超过256字节
正确时的返回JSON数据包如下:
{&errcode&:0,&errmsg&:&ok&}
错误时的返回JSON数据包如下(示例为无效菜单名长度):
{&errcode&:40018,&errmsg&:&invalid button name size&}
3、查询菜单
使用接口创建自定义菜单后,开发者还可使用接口查询自定义菜单的结构。
http请求方式:GET
对应创建接口,正确的Json返回结果:
{&menu&:{&button&:[{&type&:&click&,&name&:&今日歌曲&,&key&:&V1001_TODAY_MUSIC&,&sub_button&:[]},{&type&:&click&,&name&:&歌手简介&,&key&:&V1001_TODAY_SINGER&,&sub_button&:[]},{&name&:&菜单&,&sub_button&:[{&type&:&view&,&name&:&搜索&,&url&:&http://www.soso.com/&,&sub_button&:[]},{&type&:&view&,&name&:&视频&,&url&:&http://v.qq.com/&,&sub_button&:[]},{&type&:&click&,&name&:&赞一下我们&,&key&:&V1001_GOOD&,&sub_button&:[]}]}]}}
4、删除菜单
使用接口创建自定义菜单后,开发者还可使用接口删除当前使用的自定义菜单。
http请求方式:GET
对应创建接口,正确的Json返回结果:
{&errcode&:0,&errmsg&:&ok&}
5、事件处理
用户点击自定义菜单后,如果菜单按钮设置为click类型,则微信会把此次点击事件推送给开发者,注意view类型(跳转到URL)的菜单点击不会上报。
推送XML数据包示例:&xml&
&ToUserName&&![CDATA[toUser]]&&/ToUserName&
&FromUserName&&![CDATA[FromUser]]&&/FromUserName&
&CreateTime&&/CreateTime&
&MsgType&&![CDATA[event]]&&/MsgType&
&Event&&![CDATA[CLICK]]&&/Event&
&EventKey&&![CDATA[EVENTKEY]]&&/EventKey&
&/xml&复制代码参数说明:
参数& & & & 描述
ToUserName& & & & 开发者微信号
FromUserName& & & & 发送方帐号(一个OpenID)
CreateTime& & & & 消息创建时间 (整型)
MsgType& & & & 消息类型,event
Event& & & & 事件类型,CLICK
EventKey& & & & 事件KEY值,与自定义菜单接口中KEY值对应
三、实例讲解
还接着上一篇文章讲。微信公众账号开发教程(三) 实例入门:机器人(附源码)
我们将在上一篇文章基础上,添加自定义菜单功能。
1、获取access_token
首先需要得到AppId和AppSecret
当你成为开发者后,自然能够在,开发者模式,便可看到这两个值,可以重置。
然后调用按照二.1中所示,进行操作。
注意:access_token有过期时间,如果过期,需要重新获取。
代码如下:& && & private static DateTime GetAccessToken_T
& && &&&/// &summary&
& && &&&/// 过期时间为7200秒
& && &&&/// &/summary&
& && &&&private static int Expires_Period = 7200;
& && &&&/// &summary&
& && &&&///
& && &&&/// &/summary&
& && &&&private static string mAccessT
& && &&&/// &summary&
& && &&&///
& && &&&/// &/summary&
& && &&&public static string AccessToken
& && &&&{
& && && && &get
& && && && &{
& && && && && & //如果为空,或者过期,需要重新获取
& && && && && & if (string.IsNullOrEmpty(mAccessToken) || HasExpired())
& && && && && & {
& && && && && && &&&//获取
& && && && && && &&&mAccessToken = GetAccessToken(AppID, AppSecret);
& && && && && & }
& && && && && & return mAccessT
& && && && &}
& && &&&}
& && &&&/// &summary&
& && &&&///
& && &&&/// &/summary&
& && &&&/// &param name=&appId&&&/param&
& && &&&/// &param name=&appSecret&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private static string GetAccessToken(string appId, string appSecret)
& && &&&{
& && && && &string url = string.Format(&https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}&, appId, appSecret);
& && && && &string result = HttpUtility.GetData(url);
& && && && &XDocument doc = XmlUtility.ParseJson(result, &root&);
& && && && &XElement root = doc.R
& && && && &if (root != null)
& && && && &{
& && && && && & XElement access_token = root.Element(&access_token&);
& && && && && & if (access_token != null)
& && && && && & {
& && && && && && &&&GetAccessToken_Time = DateTime.N
& && && && && && &&&if (root.Element(&expires_in&)!=null)
& && && && && && &&&{
& && && && && && && && &Expires_Period = int.Parse(root.Element(&expires_in&).Value);
& && && && && && &&&}
& && && && && && &&&return access_token.V
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&GetAccessToken_Time = DateTime.MinV
& && && && && & }
& && && && &}
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 判断Access_token是否过期
& && &&&/// &/summary&
& && &&&/// &returns&bool&/returns&
& && &&&private static bool HasExpired()
& && &&&{
& && && && &if (GetAccessToken_Time != null)
& && && && &{
& && && && && & //过期时间,允许有一定的误差,一分钟。获取时间消耗
& && && && && & if (DateTime.Now & GetAccessToken_Time.AddSeconds(Expires_Period).AddSeconds(-60))
& && && && && & {
& && && && && && &&&
& && && && && & }
& && && && &}
& && && && &
& && &&&}
复制代码2、设置菜单
菜单需根据需要,按照实际要求进行设定。
这里我们提供天气查询功能,将常用的城市列出来,点击即可查询。
然后还提供了友情链接,这里提供了view类型的菜单,直接可以跳转至URL页面,为跳转做个好的演示。
具体菜单如下:{
& & &button&: [
& && &&&{
& && && && &&name&: &链接&,
& && && && &&sub_button&: [
& && && && && & {
& && && && && && &&&&type&: &view&,
& && && && && && &&&&name&: &搜索&,
& && && && && && &&&&url&: &http://www.baidu.com/&
& && && && && & },
& && && && && & {
& && && && && && &&&&type&: &view&,
& && && && && && &&&&name&: &视频&,
& && && && && && &&&&url&: &http://v.qq.com/&
& && && && && & },
& && && && && & {
& && && && && && &&&&type&: &click&,
& && && && && && &&&&name&: &赞一下我们&,
& && && && && && &&&&key&: &BTN_GOOD&
& && && && && & }
& && && && &]
& && &&&},
& && &&&{
& && && && &&name&: &查询天气&,
& && && && &&sub_button&: [
& && && && && & {
& && && && && && &&&&type&: &click&,
& && && && && && &&&&name&: &武汉&,
& && && && && && &&&&key&: &BTN_TQ_WUHAN&
& && && && && & },
& && && && && & {
& && && && && && &&&&type&: &click&,
& && && && && && &&&&name&: &上海&,
& && && && && && &&&&key&: &BTN_TQ_SHANGHAI&
& && && && && & },
& && && && && & {
& && && && && && &&&&type&: &click&,
& && && && && && &&&&name&: &北京&,
& && && && && && &&&&key&: &BTN_TQ_BEIJING&
& && && && && & }
& && && && &]
& && &&&},
& && &&&{
& && && && &&type&: &click&,
& && && && &&name&: &帮助&,
& && && && &&key&: &BTN_HELP&
& && &&&}
& & ]
}复制代码3、管理菜单
因为菜单的变更没有那么频繁,因此通过txt文件来设置菜单,并通过管理界面来管理菜单。
主要的管理功能:
1)从文件加载菜单
2)创建菜单。即将菜单通知微信服务端,并更新至微信客户端
3)查询菜单。获取当前系统的菜单。
4)删除菜单。从微信服务器删除菜单,也可以删除后再创建。
实现代码如下:& & public class MenuManager
& & {
& && &&&/// &summary&
& && &&&/// 菜单文件路径
& && &&&/// &/summary&
& && &&&private static readonly string Menu_Data_Path = System.AppDomain.CurrentDomain.BaseDirectory + &/Data/menu.txt&;
& && &&&/// &summary&
& && &&&/// 获取菜单
& && &&&/// &/summary&
& && &&&public static string GetMenu()
& && &&&{
& && && && &string url = string.Format(&https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}&, Context.AccessToken);
& && && && &return HttpUtility.GetData(url);
& && &&&}
& && &&&/// &summary&
& && &&&/// 创建菜单
& && &&&/// &/summary&
& && &&&public static void CreateMenu(string menu)
& && &&&{
& && && && &string url = string.Format(&https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}&, Context.AccessToken);
& && && && &//string menu = FileUtility.Read(Menu_Data_Path);
& && && && &HttpUtility.SendHttpRequest(url, menu);
& && &&&}
& && &&&/// &summary&
& && &&&/// 删除菜单
& && &&&/// &/summary&
& && &&&public static void DeleteMenu()
& && &&&{
& && && && &string url = string.Format(&https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}&, Context.AccessToken);
& && && && &HttpUtility.GetData(url);
& && &&&}
& && &&&/// &summary&
& && &&&/// 加载菜单
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public static string LoadMenu()
& && &&&{
& && && && &return FileUtility.Read(Menu_Data_Path);
& && &&&}
& & }复制代码4、基本方法
上面的代码,其实我们对一些公共功能做了封装。如进行get请求、POST提交等操作,读取文件等。
这里我们提供进行get、Post提交的方法案例代码,如果使用,建议优化。using S
using System.IO;
using System.N
using System.T
using System.W
namespace Yank.WeiXin.Robot.Utility
{
& & /// &summary&
& & /// Http帮助类
& & /// &/summary&
& & class HttpUtility
& & {
& && &&&/// &summary&
& && &&&/// 发送请求
& && &&&/// &/summary&
& && &&&/// &param name=&url&&Url地址&/param&
& && &&&/// &param name=&data&&数据&/param&
& && &&&public static string SendHttpRequest(string url, string data)
& && &&&{
& && && && &return SendPostHttpRequest(url,&application/x-www-form-urlencoded&,data);
& && &&&}
& && &&&/// &summary&
& && &&&///
& && &&&/// &/summary&
& && &&&/// &param name=&url&&&/param&
& && &&&/// &returns&&/returns&
& && &&&public static string GetData(string url)
& && &&&{
& && && && &return SendGetHttpRequest(url,&application/x-www-form-urlencoded&);
& && &&&/// &summary&
& && &&&/// 发送请求
& && &&&/// &/summary&
& && &&&/// &param name=&url&&Url地址&/param&
& && &&&/// &param name=&method&&方法(post或get)&/param&
& && &&&/// &param name=&method&&数据类型&/param&
& && &&&/// &param name=&requestData&&数据&/param&
& && &&&public static string SendPostHttpRequest(string url,string contentType,string requestData)
& && &&&{
& && && && &WebRequest request = (WebRequest)HttpWebRequest.Create(url);
& && && && &request.Method = &POST&;
& && && && &byte[] postBytes =
& && && && &request.ContentType = contentT
& && && && &postBytes = Encoding.UTF8.GetBytes(requestData);
& && && && &request.ContentLength = postBytes.L
& && && && &using (Stream outstream = request.GetRequestStream())
& && && && &{
& && && && && & outstream.Write(postBytes, 0, postBytes.Length);
& && && && &}
& && && && &string result = string.E
& && && && &using (WebResponse response = request.GetResponse())
& && && && &{
& && && && && & if (response != null)
& && && && && & {& && && && && && &&&
& && && && && && &&&using (Stream stream = response.GetResponseStream())
& && && && && && &&&{
& && && && && && && && &using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
& && && && && && && && &{
& && && && && && && && && & result = reader.ReadToEnd();
& && && && && && && && &}
& && && && && && &&&}
& && && && && && &&&
& && && && && & }
& && && && &}
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 发送请求
& && &&&/// &/summary&
& && &&&/// &param name=&url&&Url地址&/param&
& && &&&/// &param name=&method&&方法(post或get)&/param&
& && &&&/// &param name=&method&&数据类型&/param&
& && &&&/// &param name=&requestData&&数据&/param&
& && &&&public static string SendGetHttpRequest(string url, string contentType)
& && &&&{
& && && && &WebRequest request = (WebRequest)HttpWebRequest.Create(url);
& && && && &request.Method = &GET&;
& && && && &request.ContentType = contentT
& && && && &string result = string.E
& && && && &using (WebResponse response = request.GetResponse())
& && && && &{
& && && && && & if (response != null)
& && && && && & {
& && && && && && &&&using (Stream stream = response.GetResponseStream())
& && && && && && &&&{
& && && && && && && && &using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
& && && && && && && && &{
& && && && && && && && && & result = reader.ReadToEnd();
& && && && && && && && &}
& && && && && && &&&}
& && && && && & }
& && && && &}
& && && && &
& && &&&}
& & }
}
using S
using System.Xml.L
using Newtonsoft.J
namespace Yank.WeiXin.Robot.Utility
{
& & class XmlUtility
& & {
& && &&&/// &summary&
& && &&&///
& && &&&/// &/summary&
& && &&&/// &param name=&json&&&/param&
& && &&&/// &param name=&rootName&&&/param&
& && &&&/// &returns&&/returns&
& && &&&public static XDocument ParseJson(string json,string rootName)
& && &&&{
& && && && &return JsonConvert.DeserializeXNode(json, rootName);
& && &&&}
& & }
}
复制代码5、事件处理
设置了菜单,这下需要处理事件了。跟我们之前设计ASPX或者WinForm一样,都要绑定按钮的事件。这里只是通过XML消息将请求传递过来。
通过“2、设置菜单&中具体的菜单内容,我们便已经知道需要进行哪些事件处理了。对于按钮类型为view的,无须处理,它会自动跳转至指定url.
需要处理的点击事件:
2)查询某城市的天气,北京、上海、武汉
这个还要沿用上章中的事件处理器EventHandler来扩展处理。
具体的实现代码吧:using S
using System.Collections.G
using System.L
using System.T
using Yank.WeiXin.Robot.M
namespace Yank.WeiXin.Robot.Handlers
{
& & class EventHandler : IHandler
& & {
& && &&&/// &summary&
& && &&&/// 请求的xml
& && &&&/// &/summary&
& && &&&private string RequestXml { }
& && &&&/// &summary&
& && &&&/// 构造函数
& && &&&/// &/summary&
& && &&&/// &param name=&requestXml&&&/param&
& && &&&public EventHandler(string requestXml)
& && &&&{
& && && && &this.RequestXml = requestX
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理请求
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string HandleRequest()
& && &&&{
& && && && &string response = string.E
& && && && &EventMessage em = EventMessage.LoadFromXml(RequestXml);
& && && && &if (em != null)
& && && && &{
& && && && && & switch (em.Event.ToLower())
& && && && && & {
& && && && && && &&&case (&subscribe&):
& && && && && && && && &response = SubscribeEventHandler(em);
& && && && && && && && &
& && && && && && &&&case &click&:
& && && && && && && && &response = ClickEventHandler(em);
& && && && && && && && &
& && && && && & }
& && && && &}
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 关注
& && &&&/// &/summary&
& && &&&/// &param name=&em&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private string SubscribeEventHandler(EventMessage em)
& && &&&{
& && && && &//回复欢迎消息
& && && && &TextMessage tm = new TextMessage();
& && && && &tm.ToUserName = em.FromUserN
& && && && &tm.FromUserName = em.ToUserN
& && && && &tm.CreateTime = Common.GetNowTime();
& && && && &tm.Content = &欢迎您关注***,我是大哥大,有事就问我,呵呵!\n\n&;
& && && && &return tm.GenerateContent();
& && &&&}
& && &&&/// &summary&
& && &&&/// 处理点击事件
& && &&&/// &/summary&
& && &&&/// &param name=&em&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private string ClickEventHandler(EventMessage em)
& && &&&{
& && && && &string result = string.E
& && && && &if (em != null && em.EventKey != null)
& && && && &{
& && && && && & switch (em.EventKey.ToUpper())
& && && && && & {
& && && && && && &&&case &BTN_GOOD&:
& && && && && && && && &result = btnGoodClick(em);
& && && && && && && && &
& && && && && && &&&case &BTN_TQ_BEIJING&:
& && && && && && && && &result = searchWeather(&beijing&, em);
& && && && && && && && &
& && && && && && &&&case &BTN_TQ_SHANGHAI&:
& && && && && && && && &result = searchWeather(&shanghai&, em);
& && && && && && && && &
& && && && && && &&&case &BTN_TQ_WUHAN&:
& && && && && && && && &result = searchWeather(&wuhai&, em);
& && && && && && && && &
& && && && && && &&&case &BTN_HELP&:
& && && && && && && && &result = btnHelpClick(em);
& && && && && && && && &
& && && && && & }
& && && && &}
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 赞一下
& && &&&/// &/summary&
& && &&&/// &param name=&em&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private string btnGoodClick(EventMessage em)
& && &&&{
& && && && &//回复欢迎消息
& && && && &TextMessage tm = new TextMessage();
& && && && &tm.ToUserName = em.FromUserN
& && && && &tm.FromUserName = em.ToUserN
& && && && &tm.CreateTime = Common.GetNowTime();
& && && && &tm.Content = @&谢谢您的支持!&;
& && && && &return tm.GenerateContent();
& && &&&}
& && &&&/// &summary&
& && &&&/// 帮助
& && &&&/// &/summary&
& && &&&/// &param name=&em&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private string btnHelpClick(EventMessage em)
& && &&&{
& && && && &//回复欢迎消息
& && && && &TextMessage tm = new TextMessage();
& && && && &tm.ToUserName = em.FromUserN
& && && && &tm.FromUserName = em.ToUserN
& && && && &tm.CreateTime = Common.GetNowTime();
& && && && &tm.Content = @&查询天气,输入tq 城市名称\拼音\首字母&;
& && && && &return tm.GenerateContent();
& && &&&}
& && &&&/// &summary&
& && &&&/// 查询天气
& && &&&/// &/summary&
& && &&&/// &param name=&cityName&&&/param&
& && &&&/// &param name=&em&&&/param&
& && &&&/// &returns&&/returns&
& && &&&private string searchWeather(string cityName, EventMessage em)
& && &&&{
& && && && &TextMessage tm = new TextMessage();
& && && && &tm.Content = WeatherHelper.GetWeather(cityName);
& && && && &//进行发送者、接收者转换
& && && && &tm.ToUserName = em.FromUserN
& && && && &tm.FromUserName = em.ToUserN
& && && && &tm.CreateTime = Common.GetNowTime();
& && && && &return tm.GenerateContent();
& && &&&}
& & }
}复制代码6、效果图
终于大工告成,最后来看下效果图吧
52.jpg (0 Bytes, 下载次数: 2)
14:50 上传
阅读权限255
在线时间 小时
(六)获取个性二维码
一、功能介绍
在进行推广时,我们可以告诉对方,我们的微信公众账号是什么,客户可以去搜索,然后关注。二维码给我们提供了极大的便捷,只要简单一扫描,即可关注。
如果已经关注过,立刻跳入对话画面。在我们进行推广时,不再是简陋的文字,可以是一个有个性的二维码,想必会很生动。
微信对二维码提供了很好的支持,而且还可以根据需要生成不同场景的二维码。下面我们将介绍如何获取和使用二维码。
注意:限服务号,且进行了微信认证,费用300
61.jpg (0 Bytes, 下载次数: 4)
14:58 上传
二、相关接口
为了满足用户渠道推广分析的需要,公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送。
目前有2种类型的二维码,分别是临时二维码和永久二维码,前者有过期时间,最大为1800秒,但能够生成较多数量,后者无过期时间,数量较少(目前参数只支持1--1000)。两种二维码分别适用于帐号绑定、用户来源统计等场景。
用户扫描带场景值二维码时,可能推送以下两种事件:
1.& & & & 如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
2.& & & & 如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。
获取带参数的二维码的过程包括两步,首先创建二维码ticket,然后凭借ticket到指定URL换取二维码。
创建二维码ticket
每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id),分别介绍临时二维码和永久二维码的创建二维码ticket过程。
临时二维码请求说明
http请求方式: POST
POST数据格式:json
POST数据例子:{&expire_seconds&: 1800, &action_name&: &QR_SCENE&, &action_info&: {&scene&: {&scene_id&: 123}}}
永久二维码请求说明
http请求方式: POST
POST数据格式:json
POST数据例子:{&action_name&: &QR_LIMIT_SCENE&, &action_info&: {&scene&: {&scene_id&: 123}}}
参数& & & & 说明
expire_seconds& & & & 该二维码有效时间,以秒为单位。 最大不超过1800。
action_name& & & & 二维码类型,QR_SCENE为临时,QR_LIMIT_SCENE为永久
action_info& & & & 二维码详细信息
scene_id& & & & 场景值ID,临时二维码时为32位整型,永久二维码时最大值为1000
正确的Json返回结果:
{&ticket&:&gQG28DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0FuWC1DNmZuVEhvMVp4NDNMRnNRAAIEesLvUQMECAcAAA==&,&expire_seconds&:1800}
参数& & & & 说明
ticket& & & & 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码。
expire_seconds& & & & 二维码的有效时间,以秒为单位。最大不超过1800。
错误的Json返回示例:
{&errcode&:40013,&errmsg&:&invalid appid&}
全局返回码说明
使用网页调试工具调试该接口
通过ticket换取二维码
获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用。
HTTP GET请求(请使用https协议)
ticket正确情况下,http 返回码是200,是一张图片,可以直接展示或者下载。
HTTP头(示例)如下:Accept-Ranges:bytes
Cache-control:max-age=604800
Connection:keep-alive
Content-Length:28026
Content-Type:image/jpg
Date:Wed, 16 Oct :10 GMT
Expires:Wed, 23 Oct :10 +0800
Server:nginx/1.4.1
复制代码错误情况下(如ticket非法)返回HTTP错误码404。
三、具体实现
依然基于之前的机器人案例进行功能添加,直接看代码。& & /// &summary&
& & /// 二维码管理者
& & /// &/summary&
& & public class DimensionalCodeManager
& & {
& && &&&/// &summary&
& && &&&/// 临时二维码地址
& && &&&/// &/summary&
& && &&&/// 使用string.format时,报:字符串格式错误,因为其中有{
& && &&&//private const string TEMP_URL = &{\&expire_seconds\&: 1800, \&action_name\&: \&QR_SCENE\&, \&action_info\&: {\&scene\&: {\&scene_id\&: {0}}}}&;
& && &&&/// &summary&
& && &&&/// 解决办法,将原有字符串中的一个{用两个{代替
& && &&&/// &/summary&
& && &&&private const string TEMP_JSON_DATA = &{{\&expire_seconds\&: 1800, \&action_name\&: \&QR_SCENE\&, \&action_info\&: {{\&scene\&: {{\&scene_id\&: {0}}}}}}}&;
& && &&&/// &summary&
& && &&&/// 永久二维码地址
& && &&&/// &/summary&
& && &&&private const string PERMANENT_URL = &{{\&action_name\&: \&QR_LIMIT_SCENE\&, \&action_info\&: {{\&scene\&: {{\&scene_id\&: {0}}}}}}}&;
& && &&&/// &summary&
& && &&&/// 获取ticket的URL
& && &&&/// &/summary&
& && &&&private const string GET_TICKET_URL = & https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}&;
& && &&&/// &summary&
& && &&&/// 获取二维码URL
& && &&&/// &/summary&
& && &&&private const string GET_CODE_URL = &https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={0}&;
& && &&&/// &summary&
& && &&&/// 根据场景ID获取ticket
& && &&&/// &/summary&
& && &&&/// &param name=&sceneID&&场景ID&/param&
& && &&&/// &param name=&isTemp&&是否是临时二维码&/param&
& && &&&/// &returns&&/returns&
& && &&&private static string GetTicket(int sceneID, bool isTemp)
& && &&&{
& && && && &string result =
& && && && &string data = string.E
& && && && &if (isTemp)
& && && && &{
& && && && && & data = string.Format(TEMP_JSON_DATA, sceneID.ToString());
& && && && &}
& && && && &else
& && && && &{
& && && && && & if (sceneID & 0 && sceneID &= 1000)
& && && && && & {
& && && && && && &&&data = string.Format(PERMANENT_URL, sceneID);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&//scene_id不合法
& && && && && && &&&
& && && && && & }
& && && && &}
& && && && &string ticketJson = HttpUtility.GetData(string.Format(GET_TICKET_URL,Context.AccessToken));
& && && && &XDocument doc = XmlUtility.ParseJson(ticketJson, &root&);
& && && && &XElement root = doc.R
& && && && &if (root != null)
& && && && &{
& && && && && & XElement ticket = root.Element(&ticket&);
& && && && && & if (ticket != null)
& && && && && & {
& && && && && && &&&result = ticket.V
& && && && && & }
& && && && &}
& && && && &
& && &&&}
& && &&&/// &summary&
& && &&&/// 创建临时二维码
& && &&&/// &/summary&
& && &&&/// &param name=&sceneID&&场景id,int类型&/param&
& && &&&/// &returns&&/returns&
& && &&&public static string GenerateTemp(int sceneID)
& && &&&{
& && && && &string ticket = GetTicket(sceneID,true);
& && && && &if (ticket == null)
& && && && &{
& && && && && &
& && && && &}
& && && && &return HttpUtility.GetData(string.Format(GET_CODE_URL, ticket));
& && &&&}
& && &&&/// &summary&
& && &&&/// 创建临时二维码
& && &&&/// &/summary&
& && &&&/// &param name=&sceneID&&场景id,int类型&/param&
& && &&&/// &returns&&/returns&
& && &&&public static string GeneratePermanent(int sceneID)
& && &&&{
& && && && &string ticket = GetTicket(sceneID, false);
& && && && &if (ticket == null)
& && && && &{
& && && && && &
& && && && &}
& && && && &return HttpUtility.GetData(string.Format(GET_CODE_URL, ticket));
& && &&&}
& & }复制代码
阅读权限255
在线时间 小时
(七)安全策略
尽管处理微信请求的服务器,处于微信服务器的后端,但是安全问题依然不可小觑。
大概总结以下几个方面,希望引起注意。
一、设置高复杂度的Token,尽量隐藏服务地址URL
URL:即为处理微信请求的链接地址
Token:用户身份凭证
申请成为开发者或者修改URL\Token时,微信会通过Get请求访问URL,验证签名,其中需要Token。
过程相当于一次握手,如果握手成功,可进行后续的通信。
71.jpg (0 Bytes, 下载次数: 0)
15:02 上传
成为开发者后,我们也可以进行修改
72.jpg (0 Bytes, 下载次数: 0)
15:02 上传
面临的危险:
1、如URL和Token被破解,直接链接到其他公众账号,直接可以盗用服务。当然对于一些广告类型账号而言,这样无利可图。但是,如果是提供某种应用或者服务的公众账号,免费给其他账号提供服务,势必增加服务端压力,带来一定的风险。
2、如果URL被破解,即使token没被破解。一些不法分子,可能对该URL进行攻击,当然枪打出头鸟,想被黑客盯上也不没那么容易。呵呵
1、尽量保证服务的URL,与提供消息或者网页没有直接关系。以防止,根据URL推算得出服务URL。
2、可以使用URL重定向,将一些路径信息进行隐藏。
3、在服务中判定请求的来源,是否是微信服务器来的请求。这个可以根据请求的URL来进行判定,对于其他请求不予处理。
4、Token值,尽量复杂一些。
二、建议每次请求,都进行签名验证
在设置URL或token后,微信都会提交get请求,来访问我们后端服务。验证通过之后,微信其他请求都是通过POST方式提交。
所以在代码中,我们常常会根据请求的方式来判断是否进行签名验证。在之前的例子中,也曾这么用:& && &&&/// &summary&
& && &&&/// 处理请求,产生响应
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string Response()
& && &&&{
& && && && &string method = Request.HttpMethod.ToUpper();
& && && && &//验证签名
& && && && &if (method == &GET&)
& && && && &{
& && && && && & if (CheckSignature())
& && && && && & {
& && && && && && &&&return Request.QueryString[ECHOSTR];
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&return &error&;
& && && && && & }
& && && && &}
& && && && &//处理消息
& && && && &if (method == &POST&)
& && && && &{
& && && && && & return ResponseMsg();
& && && && &}
& && && && &return &无法处理&;
& && &&&}
复制代码尽管微信其他请求是以POST提交的,但是其URL中同样携带了签名信息,我们同样需要进行签名认证。所以为了安全起见,建议每次请求都进行签名认证。
根据这个原理,我们将代码修改如下:& && & /// &summary&
& && &&&/// 处理请求,产生响应
& && &&&/// &/summary&
& && &&&/// &returns&&/returns&
& && &&&public string Response()
& && &&&{
& && && && &string method = Request.HttpMethod.ToUpper();
& && && && &//验证签名
& && && && &if (method == &GET&)
& && && && &{
& && && && && & if (CheckSignature())
& && && && && & {
& && && && && && &&&return Request.QueryString[ECHOSTR];
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&return &error&;
& && && && && & }
& && && && &}
& && && && &//处理消息
& && && && &if (method == &POST&)
& && && && &{
& && && && && & //验证签名
& && && && && & if (CheckSignature())
& && && && && & {
& && && && && && &&&return ResponseMsg();
& && && && && & }
& && && && &}
& && && && &return &无法处理&;
& && &&&}复制代码签名算法CheckSignature(),这里不再赘述,具体可见:微信公众账号开发教程(二) 基础框架搭建
三、可以根据ToUserName 验证请求
通常我们的公众账号都对应一个openId,在处理消息时可以获得。这个openId是固定的,可以根据其判定发送者的身份信息。这种方式,可以很好的过滤无效消息或者欺骗,只有发给我的消息,我才处理。即使URL和Token被人破解,也同样能够保证后端服务,只为我们的公众账号提供服务。
& && &&&/// &summary&
& && &&&/// 是否是发给我的呢
& && &&&/// &/summary&
& && &&&/// &param name=&toUserName&&接受者&/param&
& && &&&/// &returns&bool&/returns&
& && &&&private bool IsSentToMe(string toUserName)
& && &&&{
& && && && &return string.Equals(toUserName,Context.OpenID,StringComparison.OrdinalIgnoreCase);
& && &&&}复制代码四、AppId和AppSecret
如果是服务号,还有一些高级功能,而这些高级功能需要开发者凭据:AppId和AppSecret。
根据AppId和AppSecret可以获得ACCESS_TOKEN,根据ACCESS_TOKEN就可以管理高级功能了,比如:自定义菜单。
ACESS_TOKEN有过期时间,通常为7200S。但是AppId和AppSecret是系统随机生成的,无过期时间,如果需要修改,需要登录微信公众账号管理平台进行重置。
获取Access_Token方式,通过Get请求如下URL
获取Access_Token后,就可以操作一些高级接口
创建自定义菜单,是通过http请求方式:POST(请使用https协议)
具体实现,见:微信公众账号开发教程(四)自定义菜单
ACCESS_TOKEN是通过get方法获得的,其实不太安全,如果被人窃取,其可以修改自定义菜单的链接,可以将其改为一些广告链接,或者更邪恶的链接,你这服务器直接成了人家的肉机。所以一定要保证服务器的安全。为了安全起见,建议隔一段时间重置AppId和AppSecret(微信公众平台的后台服务页面)。重要的还是要保证允许服务器的安全,具体可以见五。
五、保证服务器的安全
服务器安全要素很多,比如:保证网络安全、设置防火墙、安装杀毒软件、限制一些端口等等,这跟我们平时服务器安全要求一样,这方面资料很多,这里不再赘述。
阅读权限255
在线时间 小时
(八)Session处理
在微信窗口,输入的信息有

我要回帖

更多关于 微信多用户商城系统 的文章

 

随机推荐