详解微信公众号开发客服接口实例(附代码)
这篇文章详解微信公众号开发客服接口实例(附代码),需要的朋友可以参考下
最近,开发微信公众号,负责开发客服功能,这里简单记录下:
Kf_account.cs代码:
public partial class Kf_account : Form{private readonly DataTable adt_user = new DataTable();private readonly string as_INIFile = Application.StartupPath + "\user.ini";public Kf_account(){BindUser();}private void BindUser(){if (!File.Exists(as_INIFile)){var str = new StringBuilder();str.Append(";内容由程序自动生成,请不要修改此文件内容rn");str.Append("[total]rn");str.Append("total=rn");str.Append("[count]rn");str.Append("count=rn");str.Append("[user]rn");//StreamWriter sw = default(StreamWriter);//sw = File.CreateText(ls_INIFile);//sw.WriteLine(str.ToString());//sw.Close();File.WriteAllText(as_INIFile, str.ToString(), Encoding.Unicode);File.SetAttributes(as_INIFile, FileAttributes.Hidden);}CheckForIllegalCrossThreadCalls = false;InitializeComponent();Icon = Resource1.ico;lkl_num.Text = INIFile.ContentValue("total", "total", as_INIFile);lkl_num_c.Text = INIFile.ContentValue("count", "count", as_INIFile);pictureBox1.Visible = true;var sr = new StreamReader(as_INIFile, Encoding.Unicode);String line;int li_count = 0;adt_user.Columns.Clear();adt_user.Columns.Add("username", Type.GetType("System.String"));adt_user.Columns.Add("openid", Type.GetType("System.String"));while ((line = sr.ReadLine()) != null){li_count++;if (li_count > 6){line = SysVisitor.Current.GetFormatStr(line);DataRow newRow;newRow = adt_user.NewRow();newRow["username"] = line.Substring(0, line.LastIndexOf('='));newRow["openid"] = line.Substring(line.LastIndexOf('=') + 1);adt_user.Rows.Add(newRow);}}sr.Close();dataGridView1.AutoGenerateColumns = false;dataGridView1.DataSource = adt_user;//dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.DisplayedCells;lbl_count.Text = "共" + (li_count - 6) + "行";pictureBox1.Visible = false;}private void btn_GetUser_Click(object sender, EventArgs e){if (MessageBox.Show(@"拉取用户信息的速度取决于你的关注数与网络速度,可能需要几分钟甚至更长时间。使用此功能将消耗大量用户管理接口配额。要继续此操作吗?","提示:", MessageBoxButtons.YesNo) == DialogResult.No){return;}var thr = new Thread(Get_user_list);thr.Start();}private void Get_user_list(){File.Delete(as_INIFile);var str = new StringBuilder();str.Append(";内容由程序自动生成,请不要修改此文件内容rn");str.Append("[total]rn");str.Append("total=rn");str.Append("[count]rn");str.Append("count=rn");str.Append("[user]rn");File.WriteAllText(as_INIFile, str.ToString(), Encoding.Unicode);File.SetAttributes(as_INIFile, FileAttributes.Hidden);string ls_appid = INIFile.ContentValue("weixin", "Appid");string ls_secret = INIFile.ContentValue("weixin", "AppSecret");string access_token = "";string menu = "";if (ls_appid.Length != 18 || ls_secret.Length != 32){MessageBox.Show("你的Appid或AppSecret不对,请检查后再操作");return;}access_token = SysVisitor.Current.Get_Access_token(ls_appid, ls_secret);if (access_token == ""){MessageBox.Show("Appid或AppSecret不对,请检查后再操作");return;}menu = SysVisitor.Current.GetPageInfo("https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + access_token);if (menu.Substring(2, 7) == "errcode"){MessageBox.Show("拉取失败,返回消息:rn" + menu);}JObject json = JObject.Parse(menu);lkl_num.Text = json["total"].ToString();INIFile.SetINIString("total", "total", lkl_num.Text, as_INIFile);lkl_num_c.Text = json["count"].ToString();INIFile.SetINIString("count", "count", lkl_num_c.Text, as_INIFile);int li_count = int.Parse(json["count"].ToString());btn_GetUser.Enabled = false;pictureBox1.Visible = true;FileStream fs = null;Encoding encoder = Encoding.Unicode;for (int i = 0; i < li_count; i++){string openid, username;openid = Get_UserName(json["data"]["openid"][i].ToString());username = json["data"]["openid"][i].ToString();//INIFile.SetINIString("user", openid, username, as_INIFile);byte[] bytes = encoder.GetBytes(openid + "=" + username + " rn");fs = File.OpenWrite(as_INIFile);//设定书写的晪始位置为文件的末尾fs.Position = fs.Length;//将待写入内容追加到文件末尾fs.Write(bytes, 0, bytes.Length);fs.Close();lab_nums.Text = "已拉取" + i + "个,还剩" + (li_count - i) + "个,请耐心等待";}lab_nums.Text = "";//BindUser();btn_GetUser.Enabled = true;pictureBox1.Visible = false;MessageBox.Show("已全部拉取完毕,请重新打开该窗口");}/// <summary>///获取用户信息详情,返回json/// </summary>///<param name="as_openid">private string Get_User(string as_openid){string ls_json = "";string access_token = "";access_token = SysVisitor.Current.Get_Access_token();ls_json =SysVisitor.Current.GetPageInfo("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token + "&openid=" + as_openid + "&lang=zh_CN");return ls_json;}/// <summary>///获取用户用户的昵称/// </summary>private string Get_UserName(string as_openid){string ls_json = "";ls_json = Get_User(as_openid);string username = "";JObject json = JObject.Parse(ls_json);username = json["nickname"].ToString();username = SysVisitor.Current.GetFormatStr(username);return username;}private void btn_search_Click(object sender, EventArgs e){string username = txt_search.Text.Trim();if (string.IsNullOrWhiteSpace(username)){return;}DataRow[] datarows = adt_user.Select("username like '%" + username + "%'");var ldt = new DataTable();ldt.Columns.Clear();ldt.Columns.Add("username", Type.GetType("System.String"));ldt.Columns.Add("openid", Type.GetType("System.String"));ldt = ToDataTable(datarows);try{lbl_count.Text = ldt.Rows.Count.ToString();}catch{}dataGridView1.AutoGenerateColumns = false;dataGridView1.DataSource = ldt;}public DataTable ToDataTable(DataRow[] rows){if (rows == null || rows.Length == 0) return null;DataTable tmp = rows[0].Table.Clone(); // 复制DataRow的表结构foreach (DataRow row in rows)tmp.Rows.Add(row.ItemArray); // 将DataRow添加到DataTable中return tmp;}private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e){try{SysVisitor.Current.Wx_openid =dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Cells[1].Value.ToString();SysVisitor.Current.Wx_username =dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Cells[0].Value.ToString();//MessageBox.Show(str);grb_chat.Enabled = true;grb_chat.Text = SysVisitor.Current.Wx_username;}catch{}webBrowser_msg.DocumentText = "";string url = string.Format("https://api.weixin.qq.com/cgi-bin/customservice/getrecord?access_token={0}",SysVisitor.Current.Get_Access_token());string ls_text = @"{";ls_text += ""starttime" : " + DateTime.Now.AddDays(-3).Ticks + ",";ls_text += ""endtime" : " + DateTime.Now.Ticks + ",";ls_text += ""openid" : "" + SysVisitor.Current.Wx_openid + "",";ls_text += ""pagesize" : 1000,";ls_text += ""pageindex" : 1,";ls_text += "}";string ls_history = SysVisitor.Current.PostPage(url, ls_text);webBrowser_msg.DocumentText = ls_history;}private void btn_send_Click(object sender, EventArgs e){string ls_msg = richTextBox_msg.Text;string ls_text = @"{";ls_text += ""touser":"" + SysVisitor.Current.Wx_openid + "",";ls_text += ""msgtype":"text",";ls_text += ""text":";ls_text += "{";ls_text += ""content":"" + ls_msg + """;ls_text += "}";ls_text += "}";string url = string.Format("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}",SysVisitor.Current.Get_Access_token());string ls_isright = SysVisitor.Current.PostPage(url, ls_text);webBrowser_msg.DocumentText += "" + ls_isright + ""; } private void btn_addkf_Click(object sender, EventArgs e) { string url = string.Format("https://api.weixin.qq.com/customservice/kfaccount/add?access_token={0}", SysVisitor.Current.Get_Access_token()); //客服账号 设置 xxx@你的公众号 这样的格式才是正确的哟。 string ls_text = "{"; ls_text += ""kf_account":test2@gz-sisosoft,"; ls_text += ""nickname":"客服2","; ls_text += ""password":"12345","; ls_text += "}"; string ls_kf = @"{ 'kf_account' : 'test1@gz-sisosoft', 'nickname' : '客服1', 'password' : '123456', }"; string ls_isok = SysVisitor.Current.PostPage(url, ls_text); MessageBox.Show(ls_isok); } private void Kf_account_Load(object sender, EventArgs e) { } }
SysVisitor.cs代码:
class SysVisitor {private static SysVisitor visit = null;public static SysVisitor Current{get{if (visit == null)visit = new SysVisitor();return visit;}}/// <summary>/// 获取access_token/// </summary>///<param name="appid">appid///<param name="secret">appsecret/// <returns></returns>public string Get_Access_token(string appid, string appsecret){string secondappid = INIFile.ContentValue("weixin", "secondappid");if (appid.ToLower() == secondappid.ToLower()){string ls_time = INIFile.ContentValue("weixin", "gettime");Decimal ldt;try{ldt = Convert.ToDecimal(ls_time);if (Convert.ToDecimal(DateTime.Now.ToString("yyyyMMddHHmmss")) - ldt < 7100)//每两个小时刷新一次{return INIFile.ContentValue("weixin", "access_token");}}catch{ }}string ls_appid = appid.Replace(" ", "");string ls_secret = appsecret.Replace(" ", "");string access_token = "";string url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", ls_appid, ls_secret);string json_access_token = GetPageInfo(url);//DataTable dt = Json.JsonToDataTable(json_access_token);DataTable dt = JsonHelper.JsonToDataTable(json_access_token);try{access_token = dt.Rows[0]["access_token"].ToString();}catch{return "";}INIFile.SetINIString("weixin", "gettime", DateTime.Now.ToString("yyyyMMddHHmmss"));INIFile.SetINIString("weixin", "access_token", access_token);INIFile.SetINIString("weixin", "secondappid", ls_appid);return access_token;}/// <summary>/// 获取access_token/// </summary>public string Get_Access_token(){string ls_appid = INIFile.ContentValue("weixin", "Appid");string ls_secret = INIFile.ContentValue("weixin", "AppSecret");return Get_Access_token(ls_appid, ls_secret);}/// <summary>/// Get方法请求url并接收返回消息/// </summary>///<param name="strUrl">Url地址/// <returns></returns>public string GetPageInfo(string url){HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);HttpWebResponse response = (HttpWebResponse)request.GetResponse();string ret = string.Empty;Stream s;string StrDate = "";string strValue = "";if (response.StatusCode == HttpStatusCode.OK){s = response.GetResponseStream();////在这儿处理返回的文本StreamReader Reader = new StreamReader(s, Encoding.UTF8);while ((StrDate = Reader.ReadLine()) != null){strValue += StrDate + "rn";}//strValue = Reader.ReadToEnd();}return strValue;}/// <summary>/// Post方法/// </summary>///<param name="posturl">URL///<param name="postData">Post数据/// <returns></returns>public string PostPage(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;return string.Empty;}}/// <summary>/// 格式化字符串/// </summary>///<param name="str">/// <returns></returns>public string GetFormatStr(string str){if ("" == str)return "";else{str = str.Trim();str = str.Replace("'", "'");str = str.Replace("〈", "<");str = str.Replace("〉", ">");str = str.Replace(",", ",");return str;}}string ls_username = "";/// <summary>/// 用户名/// </summary>public string Wx_username{get{return ls_username;}set{ls_username = value;}}string ls_openid = "";/// <summary>/// Openid/// </summary>public string Wx_openid{get{return ls_openid;}set{ls_openid = value;}} }
INIFile.cs代码:
class INIFile{///// <summary>///// 设置INI文件参数///// </summary>/////<param name="section">INI文件中的段落/////<param name="key">INI文件中的关键字/////<param name="val">INI文件中关键字的数值/////<param name="filePath">INI文件的完整的路径和名称///// <returns></returns>//[DllImport("kernel32")]//private static extern long WritePrivateProfileString(//string section, string key, string val, string filePath);///// <summary>///// 获取INI文件参数///// </summary>/////<param name="section">INI文件中的段落名称/////<param name="key">INI文件中的关键字/////<param name="def">无法读取时候时候的缺省数值/////<param name="retVal">读取数值/////<param name="size">数值的大小/////<param name="filePath">INI文件的完整路径和名称//[DllImport("kernel32")]//private static extern int GetPrivateProfileString(//string section, string key, string def, StringBuilder retVal, int size, string filePath);//static string gs_FileName = System.AppDomain.CurrentDomain.BaseDirectory + "Config.ini";///// <summary>///// 获取INI文件参数///// </summary>/////<param name="as_section">INI文件中的段落名称/////<param name="as_key">INI文件中的关键字/////<param name="as_FileName">INI文件的完整路径和名称//public static string GetINIString(string as_section, string as_key, string as_FileName)//{//StringBuilder temp = new StringBuilder(255);//int i = GetPrivateProfileString(as_section, as_key, "", temp, 255, as_FileName);//return temp.ToString();//}///// <summary>///// 获取INI文件参数///// </summary>/////<param name="as_section">INI文件中的段落名称/////<param name="as_key">INI文件中的关键字/////<param name="as_FileName">INI文件的完整路径和名称//public static string GetINIString(string as_section, string as_key)//{//return GetINIString(as_section, as_key, gs_FileName);//}///// <summary>///// 设置INI文件参数///// </summary>/////<param name="as_section">INI文件中的段落/////<param name="as_key">INI文件中的关键字/////<param name="as_Value">INI文件中关键字的数值/////<param name="as_FileName">INI文件的完整路径和名称//public static long SetINIString(string as_section, string as_key, string as_Value, string as_FileName)//{//return WritePrivateProfileString(as_section, as_key, as_Value, as_FileName);//}///// <summary>///// 设置INI文件参数///// </summary>/////<param name="as_section">INI文件中的段落/////<param name="as_key">INI文件中的关键字/////<param name="as_Value">INI文件中关键字的数值//public static long SetINIString(string as_section, string as_key, string as_Value)//{//return SetINIString(as_section, as_key, as_Value, gs_FileName);//}/// <summary>/// 写入INI文件/// </summary>///<param name="section">节点名称[如[TypeName]]///<param name="key">键///<param name="val">值///<param name="filepath">文件路径/// <returns></returns>[DllImport("kernel32")]public static extern long WritePrivateProfileString(string section, string key, string val, string filepath);[DllImport("kernel32.dll")]public extern static int GetPrivateProfileSectionNamesA(byte[] buffer, int iLen, string fileName);/// <summary>/// 写入INI文件(section:节点名称 key:键 val:值)/// </summary>///<param name="section">节点名称///<param name="key">键///<param name="val">值/// <returns></returns>public static long SetINIString(string section, string key, string val, string as_FilePath = ""){if (as_FilePath == ""){return (WritePrivateProfileString(section, key, val, strFilePath));}else{return (WritePrivateProfileString(section, key, val, as_FilePath));}}/// <summary>/// 读取INI文件/// </summary>///<param name="section">节点名称///<param name="key">键///<param name="def">值///<param name="retval">stringbulider对象///<param name="size">字节大小///<param name="filePath">文件路径/// <returns></returns>[DllImport("kernel32")]public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retval, int size, string filePath);public static string strFilePath = Application.StartupPath + "\Config.ini";//获取INI文件默认路径public static string strSec = "";//INI文件名/// <summary>/// 读取INI文件中的内容方法 (Section 节点名称;key 键)/// </summary>///<param name="Section">节点名称///<param name="key">键/// <returns></returns>public static string ContentValue(string Section, string key, string as_FilePath = ""){StringBuilder temp = new StringBuilder(1024);if (as_FilePath == ""){GetPrivateProfileString(Section, key, "", temp, 1024, strFilePath);}else{GetPrivateProfileString(Section, key, "", temp, 1024, as_FilePath);}return temp.ToString();}/// <summary>/// 获取指定小节所有项名和值的一个列表/// </summary>///<param name="section">节 段,欲获取的小节。注意这个字串不区分大小写///<param name="buffer">缓冲区 返回的是一个二进制的串,字符串之间是用"