微信企业号开发-如何建立连接
连接将使你的企业号更具价值,你可以使用以下三种方式,连接你的企业号及企业应用:
1、企业应用调用企业号提供的接口,管理或查询企业号后台所管理的资源、或给成员发送消息等,以下称主动调用模式。
2、企业号把用户发送的消息或用户触发的事件推送给企业应用,由企业应用处理,以下称回调模式。
3、用户在微信中阅读企业应用下发的H5页面,该页面可以调用微信提供的原生接口,使用微信开放的终端能力,以下称JSAPI模式。
通过这三种连接方式的结合,你可以在企业号中建立功能强大的移动轻应用,并依托微信数亿活跃用户,帮助企业方便、快捷地实现应用的部署,并确保应用的活跃度。
一、主动调用
1、简述
主动调用是最基本的连接模式,当你的应用调用企业号时,需使用https协议、Json数据格式、UTF8编码,访问域名为https://qyapi.weixin.qq.com,数据包不需要加密。
在每次主动调用企业号接口时需要带上AccessToken参数。AccessToken参数由CorpID和Secret换取。
CorpID是企业号的标识,每个企业号拥有一个唯一的CorpID;Secret是管理组凭证密钥。
系统管理员可通过管理端的权限管理功能创建管理组,分配管理组对应用、通讯录、接口的访问权限。完成后,管理组即可获得唯一的secret。系统管理员可通过权限管理查看所有管理组的secret,其他管理员可通过设置中的开发者凭据查看。
当企业应用调用企业号接口时,企业号后台为根据此次访问的AccessToken,校验访问的合法性以及所对应的管理组的管理权限以返回相应的结果。
注:你应该审慎配置管理组的权限,够用即好,权限过大会增加误操作可能性及信息安全隐患。
2、获取AccessToken
AccessToken是企业号的全局唯一票据,调用接口时需携带AccessToken。
AccessToken需要用CorpID和Secret来换取,不同的Secret会返回不同的AccessToken。正 常情况下AccessToken有效期为7200秒,有效期内重复获取返回相同结果,并自动续期。由于获取access_token的api调用次数非常 有限,建议企业全局存储与更新access_token,频繁刷新access_token会导致api调用受限,影响自身业务。
- 请求说明
Https请求方式: GET
https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=id&corpsecret=secrect
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
corpid | 是 | 企业Id |
corpsecret | 是 | 管理组的凭证密钥 |
- 权限说明
每个secret代表了对应用、通讯录、接口的不同权限;不同的管理组拥有不同的secret。
- 返回说明
a)正确的Json返回结果:
- {
- "access_token": "accesstoken000001",
- }
参数 | 说明 |
---|---|
access_token | 获取到的凭证 |
b)错误的Json返回示例:
- {
- "errcode": 43003,
- "errmsg": "require https"
- }
3、主动调用的频率限制
当你获取到AccessToken时,你的应用就可以成功调用企业号后台所提供的各种接口以管理或访问企业号后台的资源或给企业号成员发消息。
为了防止企业应用的程序错误而引发企业号服务器负载异常,默认情况下,每个企业号调用接口都有一定的频率限制,当超过此限制时,调用对应接口会收到相应错误码。
以下是当前默认的频率限制,企业号后台可能会根据运营情况调整此阈值:
- 基础频率
每企业调用单个cgi/api不可超过1000次/分,30000次/小时
每ip调用单个cgi/api不可超过2000次/分,60000次/小时
每ip获取AccessToken不可超过300次/小时
- 发消息频率
每企业不可超过200次/分钟;不可超过帐号上限数*30人次/天
- 创建帐号频率
每企业创建帐号数不可超过帐号上限数*3/月
二、回调模式
官方解释
1、开启应用的回调模式
在回调模式下,企业不仅可以主动调用企业号接口,还可以接收用户的消息或事件。接收的信息使用XML数据格式、UTF8编码,并以AES方式加密.
企业号的每个应用都有自己的回调模式开关。在管理端开启并设置好相关参数后,此应用的回调模式才生效。
针对加解密的处理,微信提供了各种语言的库,企业可以在附录中下载。
当你开启应用的回调模式时,企业号会要求你填写应用的URL、Token、EncodingAESKey三个参数。
URL是企业应用接收企业号推送请求的访问协议和地址,支持http或https协议。
Token可由企业任意填写,用于生成签名。
EncodingAESKey用于消息体的加密,是AES密钥的Base64编码。
验证URL、Token以及加密的详细处理请参考后续'接收消息时的加解密处理'的部分。
验证URL有效性
当你提交以上信息时,企业号将发送GET请求到填写的URL上,GET请求携带四个参数,企业在获取时需要做urldecode处理,否则会验证不成功
参数 | 描述 | 是否必带 |
---|---|---|
msg_signature | 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体 | 是 |
timestamp | 时间戳 | 是 |
nonce | 随机数 | 是 |
echostr | 加密的随机字符串,以msg_encrypt格式提供。需要解密并返回echostr明文,解密后有random、msg_len、msg、$CorpID四个字段,其中msg即为echostr明文 | 首次校验时必带 |
企业通过参数msg_signature对请求进行校验,如果确认此次GET请求来自企业号,那么企业应用对echostr参数解密并原样返回echostr明文(不能加引号),则接入验证生效,回调模式才能开启。
后续回调企业时都会在请求URL中带上以上参数(echostr除外),校验方式与首次验证URL一致。
2、使用回调模式
企业号在回调企业URL时,会对消息体本身做AES加密,以XML格式POST到企业应用的URL上;企业在被动回复时,也需要对数据加密,以XML格式返回给微信。企业的回复支持文本、图片、语音、视频、图文等格式。
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。如果在调试中,发现员工无法收到响应的消息,可以检查是否消息处理超时。
关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime排重。
假如企业无法保证在五秒内处理并回复,可以直接回复空串,企业号不会对此作任何处理,并且不会发起重试。这种情况下,可以使用发消息接口进行异步回复。
假设企业回调URL为http://api.3dept.com。
- 请求说明:
http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323
- 回调数据格式:
- <xml>
- <ToUserName><![CDATA[toUser]]</ToUserName>
- <AgentID><![CDATA[toAgentID]]</AgentID>
- <Encrypt><![CDATA[msg_encrypt]]</Encrypt>
- </xml>
1.msg_encrypt为经过加密的密文 2.AgentID为接收的应用id,可在应用的设置页面获取 3.ToUserName为企业号的CorpID
企业需要对msg_signature进行校验,并解密msg_encrypt,得出msg的原文。
- 回复给微信的数据格式:
- <xml>
- <Encrypt><![CDATA[msg_encrypt]]></Encrypt>
- <MsgSignature><![CDATA[msg_signature]]></MsgSignature>
- <TimeStamp>timestamp</TimeStamp>
- <Nonce><![CDATA[nonce]]></Nonce>
- </xml>
3、接收消息时的加解密处理
企业可以直接使用微信提供的库进行加解密的处理,目前提供的有c++/python/php/java/c#等语言版本。代码提供了解密、加密、验 证URL三个接口,企业可根据自身需要下载(参见附录)。以下为库函数的使用说明(以c++为例),更详细的加解密方案请参考附录。
1)解密函数
- int DecryptMsg(const string &sMsgSignature, const string &sTimeStamp, const string &sNonce, const string &sPostData, string &sMsg);
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
sMsgSignature | 是 | 从回调URL中获取的msg_signature参数 |
sTimeStamp | 是 | 从回调URL中获取的timestamp参数 |
sNonce | 是 | 从回调URL中获取的nonce参数 |
sPostData | 是 | 从回调URL中获取的整个post数据 |
sMsg | 是 | 用于返回解密后的msg,以xml组织 |
- 返回说明
请参阅附录加密部分。
2)加密函数
- int EncryptMsg(const string &sReplyMsg, const string &sTimeStamp, const string &sNonce, string &sEncryptMsg);
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
sReplyMsg | 是 | 返回的消息体原文 |
sTimeStamp | 是 | 时间戳,调用方生成 |
sNonce | 是 | 随机数,调用方生成 |
sEncryptMsg | 是 | 用于返回的密文,以xml组织 |
- 返回说明
请参阅附录加密部分。
3)验证URL函数
- int VerifyURL(const string &sMsgSignature, const string &sTimeStamp, const string &sNonce, const string &sEchoStr, string &sReplyEchoStr);
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
sMsgSignature | 是 | 从回调URL中获取的msg_signature参数 |
sTimeStamp | 是 | 从回调URL中获取的timestamp参数 |
sNonce | 是 | 从回调URL中获取的nonce参数 |
sEchoStr | 是 | 从回调URL中获取的echostr参数。注意,此参数必须是urldecode后的值 |
sReplyEchoStr | 是 | 解密后的echostr,用于回包。注意,必须原样返回,不要做加引号或其它处理 |
- 返回说明
请参阅附录加密部分。
详细步骤
在配置上有几个注意的地方。
1、首要要有一个ICP备案的域名,一定要有ICP备案,后面需要;
2、EncodeAESKey不能随机生成,之前官网提供是不能使用的,目前不知道,EncodeAESKey生成规则是32位明文经过base64加密后,去掉“=”,形成的43位密钥;
3、替换JCE包,重启服务
4、JDK版本要大于等于1.6
5、回调模式和主动调用模式在消息发送上也有很大不同:
A:回调模式下,被动发送的消息需要时xml格式并进行加密,加密规则是首先进行AES加密,然后进行base64加密。
B:主动发送消息,格式为json格式,不需要加密,但需要token
6、回调模式接受到真正的消息内容之后,注意回复,空消息即可,否则微信会认为消息接受失败,会再次发送同一消息
7、在接受消息上,回调模式先通过配置的链接,以Get形式发送一个密文,我们需要在Get中解析密文,返回给微信,微信接受消息无误之后,才会以Post形式将加密的真正内容发送过来,
8、主动调用模式是企业号给员工发消息,回调模式则是员工向企业号发送消息,
消息通过第三方服务器处理,最后经过微信服务器把消息发送给用户
要开启企业号的回调模式,首先要进行URL验证,也就是说,你必须要有一个服务器,来保证在公网环境下能够访问你的这个URL,然后才能接着往下走。(如果没有服务器的话,建议使用BAE比较好)。
2. 创建一个web项目,(注意必须是Dynamic Web Project项目),然后创建一个servlet类,来处理企业号发送的请求,命名任意,代码如下:
Java code
package org.yhxz.weixin.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
/**
* 核心请求处理类
*/
public class CoreServlet extends HttpServlet {
private static final long serialVersionUID = 4440739483644821986L;
String sToken = "5XaQ8cG6x2pULd";//这个Token是随机生成,但是必须跟企业号上的相同
String sCorpID = "wx4edd47d3a6r4r991";//这里是你企业号的CorpID
String sEncodingAESKey = "jWmYm7qjusnxu65ZRjGtBxmz3KA1tkAj3ykkR6q2B2C";//这个EncodingAESKey是随机生成,但是必须跟企业号上的相同
/**
* 确认请求来自微信服务器
* @throws IOException
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
// 微信加密签名
String sVerifyMsgSig = request.getParameter("msg_signature");
// 时间戳
String sVerifyTimeStamp = request.getParameter("timestamp");
// 随机数
String sVerifyNonce = request.getParameter("nonce");
// 随机字符串
String sVerifyEchoStr = request.getParameter("echostr");
String sEchoStr; //需要返回的明文
PrintWriter out = response.getWriter();
WXBizMsgCrypt wxcpt;
try {
wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce, sVerifyEchoStr);
// 验证URL成功,将sEchoStr返回
out.print(sEchoStr);
} catch (AesException e1) {
e1.printStackTrace();
}
}
/**
* 处理微信服务器发来的消息
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO 消息的接收、处理、响应
}
}
联系QQ877507054索要完整版代码
3. 接下来就要导入官方的业务类了,然后将其导入到你的项目中。这个可以在官方文档上下载到(注意,虽然官方下载的实例代码中也有验证的代码,但是不建议使用哪个Sample.java,如果不信的可以试试看,反正我用这个是没通)
下载地址是:
http://qydev.weixin.qq.com/java.zip,
请开发者使用jdk1.6或以上的版本。针对org.apache.commons.codec.binary.Base64,需要导入jar包commons-codec-1.9(或comm ons-codec-1.8等其他版本),我们有提供,官方下载地址:
http://commons.apache.org/proper/commons-codec/download_codec.cgi。
4. 如果出现异常java.security.InvalidKeyException:illegal Key Size的解决方案:
在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt。如果安装了JRE,将两个jar文件放到%JRE_HOME% \lib\security目录下覆盖原来的文件,如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件。
5. 下来就是对web.xml文件的配置,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?xml version= "1.0" encoding= "UTF-8" ?> <web-app version= "2.5" xmlns= "http://java.sun.com/xml/ns/javaee" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http: //java.sun.com/xml/ns/javaee http: //java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>coreServlet</servlet-name> <servlet- class > org.yhxz.course.servlet.CoreServlet </servlet- class > </servlet> <!-- url-pattern中配置的/coreServlet用于指定该Servlet的访问路径 --> <servlet-mapping> <servlet-name>coreServlet</servlet-name> <url-pattern>/coreServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app> |
6. 然后将你的项目发布到服务器上,在浏览器中输入URL,如果在你的Tomcat的控制台上出现NullPointException异常,就说明没有问题(出现的原因是:请求的数据为空,这个你懂得)。
7. 接下来就在企业号后台上的操作了,开启回调模式,输入你的URL,随机生成token和EncodingAESKey,点击提交就可以验证通过,注意一定要代码中的和企业号上的token和EncodingAESKey是要一致的。
三、Weixin JS接口
Weixin JS接口是微信为你的H5应用提供开放原生能力的接口,你的应用可以利用这些接口使用更多的微信原生能力和微信的操控能力, 以使得你的应用有更强大的智能,更好的用户体验。
除了以下章节所描述的各类接口。拍照、上传图片、扫码、微信支付、地理位置上报等更多的接口已经或正在抓紧开放中,更多信息也请参考微信相关网站了解.
1、隐藏微信中网页右上角按钮
企业号在有需要时(如不需要用户分享某个页面),可在网页中通过JavaScript代码隐藏网页右上角按钮。
- 接口调用代码(JavaScript)
- function onBridgeReady(){
- WeixinJSBridge.call('hideOptionMenu');
- }
- if (typeof WeixinJSBridge == "undefined"){
- if( document.addEventListener ){
- document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
- }else if (document.attachEvent){
- document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
- document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
- }
- }else{
- onBridgeReady();
- }
- 返回说明
隐藏底部导航栏没有返回值。(需要显示请把hideOptionMenu换成showOptionMenu)
2、隐藏微信中网页底部导航栏
企业号在有需要时(如认为用户在该页面不会用到浏览器前进后退功能),可在网页中通过JavaScript代码隐藏网页底部导航栏。
- 接口调用代码(JavaScript)
- function onBridgeReady(){
- WeixinJSBridge.call('hideToolbar');
- }
- if (typeof WeixinJSBridge == "undefined"){
- if( document.addEventListener ){
- document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
- }else if (document.attachEvent){
- document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
- document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
- }
- }else{
- onBridgeReady();
- }
- 返回说明
隐藏底部导航栏没有返回值。(需要显示顶部导航栏,请把hideToolbar换成showToolbar)
3、网页获取用户网络状态
为了方便开发者根据用户的网络状态来提供不同质量的服务,企业号可以在企业号内部的网页中使用JavaScript代码调用来获取网络状态。
- 接口调用代码(JavaScript)
- function onBridgeReady(){
- WeixinJSBridge.invoke('getNetworkType',{},
- function(e){
- WeixinJSBridge.log(e.err_msg);
- });
- }
- if (typeof WeixinJSBridge == "undefined"){
- if( document.addEventListener ){
- document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
- }else if (document.attachEvent){
- document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
- document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
- }
- }else{
- onBridgeReady();
- }
- 返回说明
获取用户网络状态的返回值如下:
- network_type:wifi wifi网络
- network_type:edge 非wifi,包含3G/2G
- network_type:fail 网络断开连接
- network_type:wwan(2g或者3g)
4、关闭当前网页窗口
在微信内置浏览器中被访问的网页,可使用该JavaScript代码关闭当前网页。
主要使用场景: 微信用户在企业号会话中点击外链到达企业号的网页,在用户完成操作后,企业号(网页方)可调用此接口关闭当前网页窗口,使用户返回会话。
- 接口调用代码(JavaScript)
- WeixinJSBridge.invoke('closeWindow',{},function(res){
- //alert(res.err_msg);
- });
- 返回说明
返回值 | 说明 |
---|---|
err_msg | 关闭成功返回“close_window:ok”,关闭失败返回“close_window:error”。 |
【编辑推荐】