這次我們來一起研究一下“客服消息”,首先明确一下“客服消息”的概念。這不同于之前的“被動響應消息”,也就是說并不是之前“你一言我一語的即時響應”,可能在某種情況下你需要給不同的人主動發送消息,例如你的餐館推出了新的川菜,那麼你需要給喜歡川菜的人發送消息,而并不是等着被人發送“有什麼新菜”後,然後回報給客戶,我推出了什麼什麼的。
說道這裡可能有人會問,那不是群發嗎?微信不是每天隻能發一條嗎?服務号每個月發一條嗎?答案很明确微信說的是“客服消息”,也不是群發,它跟群發的差別就在于隻要關注了我,那麼我就可以群發給你消息,而為了不讓使用者感到讨厭,微信作了嚴格的群發條數限制。而“客服消息”則是隻有關注你的人向你發送了消息,你才能主動推送。就像打電話隻有人家問過你問題了,你才能回答,并且繼續跟進回答。再舉一個例子:你通過被人知道了我的手機号,存下來了,你突然給我打電話,我肯定是抵觸的。但是如果我給你打過電話,你通過來電顯示知道了我的号碼,以後再給我打電話,說明我們是認識的,我最少不會抵觸。這就使群發/被動響應/客服消息的本質差別。
就像我們可以通過收集電話号碼,手機自己的客戶資訊一樣,一旦他們的資訊被我們收錄。那麼我們就可以突破群發條數的限制了,按照微信的限制群發一個月隻能一條(服務号),但是“客服消息”則可以一天50000條,足夠用了。
下面的問題就是如何手機客戶的“手機号”了,微信裡面有一個OPENID,這就使手機号了,這個是關注你的使用者的唯一辨別,這個辨別是不會變的,但是同一個使用者關注不同的微信号,那麼他在不同微信号中的ID是不一樣的。如何取得OPENID呢?
網上找了些資料,有的說的的确是錯誤的,有的還說要通過OAuth 2.0授權才可以,這個的确可以,但是太複雜了吧,通過我的測試得出了這樣的結論“隻要使用者和你的公共微信好發生互動”就可以取得他的OPENID了。就如同打電話一樣,隻要使用者給你打了電話,你一定知道他的電話了。在微信裡是這樣的:使用者隻要發資訊給你,或者點了某個菜單,發過來的資訊都會有一個“FromUserName”,這個就使OPENID了。我們可以建立一個資料庫來收集這些寶貴的使用者身份資訊,也就是記錄他的“電話号碼”,有了電話号碼,我們就可以以後經常與客戶主動打電話了。我做這樣的一個實驗:
首先記錄使用者的OPENID在OnLoad函數第二行裡面加上一個 WriteLog(wx.FromUserName);把它記錄在一個文本檔案中
protected void Page_Load(object sender, EventArgs e)
{
wxmessage wx = GetWxMessage();
WriteLog(wx.FromUserName);
string res = "";
if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")
{
string content = "";
if (!wx.EventKey.Contains("qrscene_"))
{
content = "/:rose歡迎北京永傑友信科技有限公司/:rose\n直接回複“你好”";
res = sendTextMessage(wx, content);
}
else
{
content = "二維碼參數:\n" + wx.EventKey.Replace("qrscene_", "");
res = sendTextMessage(wx, content);
}
}
else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.ToLower() == "scan")
{
string str = "二維碼參數:\n" + wx.EventKey;
res = sendTextMessage(wx, str);
}
else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")
{
if(wx.EventKey=="HELLO")
res = sendTextMessage(wx, "你好,歡迎使用北京永傑友信科技有限公司公共微信平台!");
}
else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "LOCATION")
{
res = sendTextMessage(wx, "您的位置是經度:" + wx.Latitude + ",次元是:" + wx.Longitude+",地理經度為:"+wx.Precision);
}
else
{
if (wx.MsgType == "text" && wx.Content == "你好")
{
res = sendTextMessage(wx, "你好,歡迎使用北京永傑友信科技有限公司公共微信平台!");
}
else if (wx.MsgType == "voice")
{
res = sendTextMessage(wx, wx.Recognition);
}
else if (wx.MsgType == "location")
{
res = sendTextMessage(wx, "您發送的位置是:" + wx.Label + ";緯度是:" + wx.Location_X + ";經度是:" + wx.Location_Y + ";縮放比例為:" + wx.Scale);
}
else
{
res = sendTextMessage(wx, "你好,未能識别消息!");
}
}
Response.Write(res);
}
WriteLog的方法是這樣的:
/// <summary>
/// 寫日志(用于跟蹤)
/// </summary>
private void WriteLog(string strMemo)
{
string filename = Server.MapPath("/logs/log.txt");
if (!Directory.Exists(Server.MapPath("//logs//")))
Directory.CreateDirectory("//logs//");
StreamWriter sr = null;
try
{
if (!File.Exists(filename))
{
sr = File.CreateText(filename);
}
else
{
sr = File.AppendText(filename);
}
sr.WriteLine(strMemo);
}
catch
{
}
finally
{
if (sr != null)
sr.Close();
}
}
這樣當客戶發送任何一種資訊給微信公共号,我們的log.txt檔案中就會記錄這個OPENID,我先打開Log.txt這個檔案看看OPENID号,我的事這樣的“oV93gjl5slD3p29yS1dOijy-pqZ8”,有了這個OPENID很多事情就都好辦了,以後我們還會介紹如何擷取客戶的資訊。這裡先說“客戶消息”吧。
下面我們建立一個新的ASPX頁面,在這個頁面裡面我就可以給這些使用者發資訊了。這個頁面(SendMessage.aspx.cs)很簡單就使兩個文本框和一個按鈕:
string MyOpenID;
string MyContent;
protected void Page_Load(object sender, EventArgs e)
{
MyOpenID = "oV93gjl5slD3p29yS1dOijy-pqZ8";
MyContent = "這是一個客服消息";
UserName.Text = MyOpenID;
Content.Text = MyContent;
}
protected void Button1_Click(object sender, EventArgs e)
{
string res = "";
string Access_Token = IsExistAccess_Token();
string posturl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + Access_Token;
string postData = "{\"touser\":\"" + UserName.Text + "\",\"msgtype\":\"text\",\"text\":{\"content\":\"" + Content.Text + "\"}}";
res = GetPage(posturl, postData);
Response.Write(res);
}
中間還用到了之前提到的3個函數:
public string GetPage(string posturl, string postData)
{
Stream outstream = null;
Stream instream = null;
StreamReader sr = null;
HttpWebResponse response = null;
HttpWebRequest request = null;
Encoding encoding = Encoding.UTF8;
byte[] data = encoding.GetBytes(postData);
// 準備請求...
try
{
// 設定參數
request = WebRequest.Create(posturl) as HttpWebRequest;
CookieContainer cookieContainer = new CookieContainer();
request.CookieContainer = cookieContainer;
request.AllowAutoRedirect = true;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
outstream = request.GetRequestStream();
outstream.Write(data, 0, data.Length);
outstream.Close();
//發送請求并擷取相應回應資料
response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程式才開始向目标網頁發送Post請求
instream = response.GetResponseStream();
sr = new StreamReader(instream, encoding);
//傳回結果網頁(html)代碼
string content = sr.ReadToEnd();
string err = string.Empty;
return content;
}
catch (Exception ex)
{
string err = ex.Message;
Response.Write(err);
return string.Empty;
}
}
/// <summary>
/// 根據目前日期 判斷Access_Token 是否超期 如果超期傳回新的Access_Token 否則傳回之前的Access_Token
/// </summary>
/// <param name="datetime"></param>
/// <returns></returns>
public static string IsExistAccess_Token()
{
string Token = string.Empty;
DateTime YouXRQ;
// 讀取XML檔案中的資料,并顯示出來 ,注意檔案路徑
string filepath = HttpContext.Current.Server.MapPath("XMLFile.xml");
StreamReader str = new StreamReader(filepath, System.Text.Encoding.UTF8);
XmlDocument xml = new XmlDocument();
xml.Load(str);
str.Close();
str.Dispose();
Token = xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText;
YouXRQ = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText);
if (DateTime.Now > YouXRQ)
{
DateTime _youxrq = DateTime.Now;
Access_token mode = GetAccess_token();
xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText = mode.access_token;
_youxrq = _youxrq.AddSeconds(int.Parse(mode.expires_in));
xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText = _youxrq.ToString();
xml.Save(filepath);
Token = mode.access_token;
}
return Token;
}
public static Access_token GetAccess_token()
{
string appid = "wx043225275885dafd";
string secret = "cb4425b24ab79ef875029cf0bf326ae9";
string strUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
Access_token mode = new Access_token();
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(strUrl);
req.Method = "GET";
using (WebResponse wr = req.GetResponse())
{
HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
string content = reader.ReadToEnd();
//Response.Write(content);
//在這裡對Access_token 指派
Access_token token = new Access_token();
token = JsonHelper.ParseFromJson<Access_token>(content);
mode.access_token = token.access_token;
mode.expires_in = token.expires_in;
}
return mode;
}
這個頁面就是這些了,打開這個頁面然後發送消息試試?很不錯吧,這樣在配合上我們的資料庫啦,什麼循環了,就可以突破了微信群發的限制,做到定項的群發消息推送了!這裡面能發很多種消息:文本,語音,視訊,圖文,圖檔等等。隻是Json而已,聰明的你一定可以舉一反三的。