@[TOC]
背景:
近期接到了涉及微信開放平臺和微信公眾平臺相關的開發(fā)需求,開發(fā)過程中踩了許多坑,把相關問題整理記錄下來以便鞏固記憶,并把總結的經驗分享出來,本篇分享微信服務號開發(fā),希望可以給大家提供幫助
一、微信各個平臺介紹
1、微信開放平臺:面向開發(fā)人員,為網站、App提供微信第三方登錄功能,為App提供支付功能。
2、微信公眾平臺:對應的是公眾號,包括訂閱號、服務號、企業(yè)號,面向運營人員和開發(fā)人員,運營可以直接登錄公眾號管理后臺查看公眾號的整體情況,開發(fā)人員則是通過調用微信提供的各種接口來增強公眾號的功能;
3、微信商戶平臺,用戶通過微信支付的錢,最終到達商戶賬號。無論是開放平臺還是公眾平臺,涉及到支付,都需要商戶平臺賬號
解釋一下什么是服務號什么是訂閱號
通過官方提供的圖片可以了解到,訂閱號的優(yōu)勢就是進行消息推送,而服務號的優(yōu)勢是能夠提供個性化的服務
二、公眾平臺介紹
公眾平臺只能通過管理員掃碼登錄,當運營、開發(fā)人員較多時,可以進行綁定運營/開發(fā)者微信號進行自行掃碼登錄(http://kf.qq.com/faq/120911VrYVrA141211FbEnq2.html)
登錄后可以在管理后臺進行一系列操作,例如:
創(chuàng)作管理:圖文素材、多媒體素材上傳
-
公眾號設置:設置公眾號關注回復內容,收到關鍵詞回復規(guī)則和內容,設置收到消息自動回復內容,自定義公眾號菜單
(注意:如果在開發(fā)者中心開啟回調URL和Token進行公眾號二次開發(fā)后,官方提供的公眾號設置功能將被關閉,后面我會針對這個場景做介紹)
管理功能:查看關注該公眾號的用戶、接收的用戶消息,可以通過管理后臺對關注的用戶進行消息回復、消息群發(fā)
統(tǒng)計功能:用戶分析、內容分析、菜單分析、圖文分析、消息分析等
三、開發(fā)前準備
-
公眾號開發(fā)切記保存好AppID和AppSecret信息(請求獲取AccessToken時用到),其中AppSecret在管理后臺不顯示,且無法查看,忘記只能重置,因此AppSecret一定要進行備份并注意防止泄露。
(官方對AccessToken進行了詳細說明https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html)
設置開發(fā)環(huán)境、測試環(huán)境、正式環(huán)境的服務器 IP為白名單,白名單以外的ip請求access_token接口會報40164錯誤,有了 access_token 才能調用微信的各種接口
四、服務器配置
開啟服務器配置,開啟以后服務號的推送信息將會傳送到所配置的服務器中,包括關注事件、事件回復、關鍵詞回復、用戶消息接收、自定義菜單等功能都將被服務器接管,并且在公眾平臺配置的一切推送規(guī)則都將被停用,需要注意。
(PS:在配置服務器URL時,由于微信會發(fā)送請求進行簽名校驗,填寫的URL必須是可以外網訪問的,開發(fā)時建議使用ngrok進行內網穿透方便調試 附上網址: https://ngrok.com/)
其他詳情可以參考服務器配置接入指南(https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html)
五、服務器驗證
開發(fā)者提交信息后,微信服務器將發(fā)送GET請求到填寫的服務器地址URL上,GET請求攜帶參數(shù)如下表所示:
參數(shù) | 描述 |
---|---|
signature | 微信加密簽名,signature結合了開發(fā)者填寫的token參數(shù)和請求中的timestamp參數(shù)、nonce參數(shù)。 |
timestamp | 時間戳 |
nonce | 隨機數(shù) |
echostr | 隨機字符串 |
開發(fā)者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數(shù)內容,則接入生效,成為開發(fā)者成功,否則接入失敗。加密/校驗流程如下:
1)將token、timestamp、nonce三個參數(shù)進行字典序排序
2)將三個參數(shù)字符串拼接成一個字符串進行sha1加密
3)開發(fā)者獲得加密后的字符串可與signature對比,標識該請求來源于微信
代碼示例:
代碼示例:
//解析
@GetMapping("/weChatParseXml")
public String parseXmlGet(@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("echostr") String echostr) {
logger.info("signature: " + signature);
logger.info("timestamp: " + timestamp);
logger.info("nonce: " + nonce);
logger.info("echostr: " + echostr);
//排序
String[] strArray = {TOKEN, timestamp, nonce}; //TOKEN為公眾平臺填寫的Token
Arrays.sort(strArray);
StringBuilder sb = new StringBuilder();
for (String str : strArray) {
sb.append(str);
}
String sortString = sb.toString();
logger.info("sortString: " + sortString);
//加密 這里主要是進行sha1加密 可以使用 SecurityUtil工具類進行加密
String myString = weChatAppletBiz.weChatParseXmlSha1(sortString);
logger.info("myString: " + myString);
//校驗
if (myString != null && myString != "" && myString.equals(signature)) {
logger.info("簽名校驗通過");
//如果檢驗成功原樣返回echostr,微信服務器接收到此輸出,才會確認檢驗完成。
return echostr;
} else {
logger.info("簽名校驗失敗");
return "";
}
}
六、消息接收
當普通微信用戶向公眾賬號發(fā)消息時,微信服務器將POST消息的XML數(shù)據(jù)包到開發(fā)者填寫的URL上。
(PS:官方提供了對文本、圖片、語音、視頻、地理位置等消息接收的方法,一般對文本的解析足以滿足大部分需求,因此下面只針對文本解析進行說明,其他詳情可以查閱上面的服務器接入指南)
請注意:
- 關于重試的消息排重,推薦使用msgid排重。
- 微信服務器在五秒內收不到響應會斷掉連接,并且重新發(fā)起請求,總共重試三次。假如服務器無法保證在五秒內處理并回復,可以直接回復空串,微信服務器不會對此作任何處理,并且不會發(fā)起重試。詳情請見“發(fā)送消息-被動回復消息”。
- 如果開發(fā)者需要對用戶消息在5秒內立即做出回應,即使用“發(fā)送消息-被動回復消息”接口向用戶被動回復消息時,可以在
公眾平臺官網的開發(fā)者中心處設置消息加密。開啟加密后,用戶發(fā)來的消息和開發(fā)者回復的消息都會被加密(但開發(fā)者通過客服接口等API調用形式向用戶發(fā)送消息,則不受影響)。關于消息加解密的詳細說明,請見“發(fā)送消息-被動回復消息加解密說明”。 關于文本消息的推送XML數(shù)據(jù)包結構如下:
文本消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>
參數(shù) | 描述 |
---|---|
ToUserName | 開發(fā)者微信號 |
FromUserName | 發(fā)送方帳號(一個OpenID) |
CreateTime | 消息創(chuàng)建時間 (整型) |
MsgType | 消息類型,文本為text |
Content | 文本消息內容 |
MsgId | 消息id,64位整型 |
代碼示例:
@PostMapping("/weChatParseXml")
public Object parseXmlPost(HttpServletRequest request) throws Exception {
logger.info("==================接收到微信消息==================");
//解析xml
// Map<String, String> stringStringMap = weChatAppletBiz.parseXml(request);
Map<String, String> messageMap = new HashMap<>();
// 從request中取得輸入流
InputStream inputStream = request.getInputStream();
// 讀取輸入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
String asXML = document.asXML();
logger.info(asXML);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子節(jié)點
List<Element> elementList = root.elements();
// 遍歷所有子節(jié)點
for (Element e : elementList) {
messageMap.put(e.getName(), e.getText());
}
// 釋放資源
inputStream.close();
logger.info("獲取到的信息:\n" + messageMap);
weChatAppletBiz.dealWithInfo(messageMap);//該方法內根據(jù)用戶行為做對應的消息推送
logger.info("==================接收微信消息結束==================");
return "";
}
實際效果:
用戶事件:
當服務器后臺獲取到用戶發(fā)送的信息后,可以根據(jù)Event參數(shù)獲取事件類型,針對不用的事件進行對應處理
事件類型分為subscribe(訂閱)、unsubscribe(取消訂閱)、 SCAN(掃描二維碼)、 CLICK(菜單點擊)、 LOCATION(地理位置)、 VIEW(菜單跳轉)
不同事件相關參數(shù)也不同,具體還請到上面分享的配置接入指南頁面,"消息管理模塊-接收事件推送"進行參考
七、客服消息
接口調用請求說明
http請求方式:
POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
消息類型分為多種,包含文本、圖片、語音、視頻、音頻、視頻、圖文、菜單,這里舉例幾個常用JSON數(shù)據(jù)包如下:
發(fā)送文本消息
{
"touser":"OPENID",
"msgtype":"text",
"text":
{
"content":"Hello World"
}
}
發(fā)送圖片消息
{
"touser":"OPENID",
"msgtype":"image",
"image":
{
"media_id":"MEDIA_ID"
}
}
發(fā)送視頻消息
{
"touser":"OPENID",
"msgtype":"video",
"video":
{
"media_id":"MEDIA_ID",
"thumb_media_id":"MEDIA_ID",
"title":"TITLE",
"description":"DESCRIPTION"
}
}
發(fā)送圖文消息(有兩種方式,這里舉例一種) 注意!!圖文消息條數(shù)限制在1條以內,如果圖文數(shù)超過1,則將會返回錯誤碼45008。 這里非常坑!
{
"touser":"OPENID",
"msgtype":"mpnews",
"mpnews":
{
"media_id":"MEDIA_ID"
}
}
發(fā)送文本消息時,還支持插入跳小程序的文字鏈
文本內容<a href="[http://www.qq.com](http://www.qq.com/)" data-miniprogram-appid="appid" data-miniprogram-path="pages/index/index">點擊跳小程序</a>
說明:
1.data-miniprogram-appid 項,填寫小程序appid,則表示該鏈接跳小程序;
2.data-miniprogram-path項,填寫小程序路徑,路徑與app.json中保持一致,可帶參數(shù);
3.對于不支持data-miniprogram-appid 項的客戶端版本,如果有herf項,則仍然保持跳href中的網頁鏈接;
4.data-miniprogram-appid對應的小程序必須與公眾號有綁定關系。
JSON數(shù)據(jù)包發(fā)送時需要注意以下幾點
1、OPENID可以通過接收參數(shù)中fromUserName字段獲得
2、msgtype一定要遵從規(guī)范,否則會出錯
3、media_id是管理員自行上傳的相關資源,上傳成功后會成為微信素材同時生成唯一的media_id,上傳方式可以從公眾平臺頁面上傳或使用curl命令進行上傳
(PS:這里我curl用的很少,大多數(shù)資源都是通過公眾平臺進行上傳,而且上傳的都是永久素材)
新增永久視頻素材的調用示例(慎用):
curl "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE" -F media=@media.file -F description='{"title":VIDEO_TITLE, "introduction":INTRODUCTION}'
參數(shù)說明
參數(shù) | 是否必須 | 說明 |
---|---|---|
title | 是 | 視頻素材的標題 |
introduction | 是 | 視頻素材的描述 |
返回說明
{
"media_id":MEDIA_ID,
"url":URL
}
返回參數(shù)說明
參數(shù) | 描述 |
---|---|
media_id | 新增的永久素材的media_id |
url | 新增的圖片素材的圖片URL(僅新增圖片素材時會返回該字段) |
八、獲取素材
調用微信系統(tǒng)的素材接口可以獲取對應的資源列表,注意!!獲取資源接口調用時有每日次數(shù)限制,不建議實時查詢,我這里是通過設計表,找恰當?shù)臅r機將數(shù)據(jù)同步到我們自己服務器中。
接口說明:
1、獲取永久素材的列表,也包含公眾號在公眾平臺官網素材管理模塊中新建的圖文消息、語音、視頻等素材
2、臨時素材無法通過本接口獲取
3、調用該接口需https協(xié)議
接口調用請求說明
http請求方式:
POST https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN
調用示例
{
"type":TYPE,
"offset":OFFSET,
"count":COUNT
}
參數(shù)說明
參數(shù) | 是否必須 | 說明 |
---|---|---|
type | 是 | 素材的類型,圖片(image)、視頻(video)、語音 (voice)、圖文(news) |
offset | 是 | 從全部素材的該偏移位置開始返回,0表示從第一個素材 返回 |
count | 是 | 返回素材的數(shù)量,取值在1到20之間 |
返回說明
永久圖文消息素材列表的響應如下:
{
"total_count": TOTAL_COUNT,
"item_count": ITEM_COUNT,
"item": [{
"media_id": MEDIA_ID,
"content": {
"news_item": [{
"title": TITLE,
"thumb_media_id": THUMB_MEDIA_ID,
"show_cover_pic": SHOW_COVER_PIC(0 / 1),
"author": AUTHOR,
"digest": DIGEST,
"content": CONTENT,
"url": URL,
"content_source_url": CONTETN_SOURCE_URL
},
//多圖文消息會在此處有多篇文章
]
},
"update_time": UPDATE_TIME
},
//可能有多個圖文消息item結構
]
}
其他類型(圖片、語音、視頻)的返回如下:
{
"total_count": TOTAL_COUNT,
"item_count": ITEM_COUNT,
"item": [{
"media_id": MEDIA_ID,
"name": NAME,
"update_time": UPDATE_TIME,
"url":URL
},
//可能會有多個素材
]
}
返回參數(shù)說明
參數(shù) | 描述 |
---|---|
total_count | 該類型的素材的總數(shù) |
item_count | 本次調用獲取的素材的數(shù)量 |
title | 圖文消息的標題 |
thumb_media_id | 圖文消息的封面圖片素材id(必須是永久mediaID) |
show_cover_pic | 是否顯示封面,0為false,即不顯示,1為true,即顯示 |
author | 作者 |
digest | 圖文消息的摘要,僅有單圖文消息才有摘要,多圖文此處為空 |
content | 圖文消息的具體內容,支持HTML標簽,必須少于2萬字符,小于1M,且此處會去除JS |
url | 圖文頁的URL,或者,當獲取的列表是圖片素材列表時,該字段是圖片的URL |
content_source_url | 圖文消息的原文地址,即點擊“閱讀原文”后的URL |
update_time | 這篇圖文消息素材的最后更新時間 |
name | 文件名稱 |
九、相關工具
- 開發(fā)者文檔,https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Global_Return_Code.html
- 在線接口調試工具,微信版PostMan,可以參考里面有哪些功能接口(https://mp.weixin.qq.com/debug/)
- WEB開發(fā)者工具,可在PC或Mac上模擬訪問微信內網頁,幫助開發(fā)者更方便地進行開發(fā)和調試。(https://mp.weixin.qq.com/cgi-bin/safecenterstatus?action=devlist&token=1654954988&lang=zh_CN)
- 公眾平臺測試賬號,在未獲取認證服務號的情況下,在這個測試賬號里面基本上所有的接口權限都開放(但部分接口存在每日調用限制,超過后當天無法再次調用,需注意!!),在開發(fā)測試階段可以使用(https://mp.weixin.qq.com/debug/)
- 接口權限查詢,登錄公眾平臺后臺管理界面后,能夠在接口權限模塊下查看當前服務號下已開通的接口權限及每日的調用次數(shù)
- Ngrok內網穿透工具( https://ngrok.com/)
十、最終效果展示
總結
微信開發(fā)過程中很容易踩坑,遇到問題建議仔細閱讀官方文檔或通過微信開放社區(qū)尋找?guī)椭?/p>