在上個月的對c#開發微信門戶及應用做了介紹,寫過了幾篇的隨筆進行分享,由于時間關系,間隔了一段時間沒有繼續寫這個系列的博客了,并不是對這個方面停止了研究,而是繼續深入探索這方面的技術,為了更好的應用起來,專心做好底層的技術開發。
微信的很重要的一個特點就是能夠利用其平臺龐大的用戶群體,因此很容易整合在crm(客戶關系管理)系統里面,服務號和訂閱好都能夠向關注者推送相關的產品消息,還能和48小時內響應消息和事件的活躍用戶進行交互對話,因此用戶信息是微信api里面非常重要的一環,本隨筆主要介紹獲取關注用戶、查看用戶信息、分組管理等方面的開發應用。
1、關注用戶列表及用戶分組信息
在微信的管理平臺上,我們可以看到自己賬號的關注者用戶,以及用戶分組信息,如下所示。
上面的管理界面,能看到關注者用戶的基礎信息,但是使用微信api獲取到的是一個稱之為openid的列表,我們先了解這個東西是什么?微信api的說明給出下面的解析:
關注者列表由一串openid(加密后的微信號,每個用戶對每個公眾號的openid是唯一的。對于不同公眾號,同一用戶的openid不同)組成。公眾號可通過本接口來根據openid獲取用戶基本信息,包括昵稱、頭像、性別、所在城市、語言和關注時間。
上面的解析意思很清楚了,就是一個用戶關注我們的公眾號,那么不管他是第幾次關注,對我們公眾號來說,都是一個確定的值;但是,一個用戶對其他公眾號,卻有著其他不同的openid。
微信提供了為數不多的幾個關鍵字信息,用來記錄用戶的相關內容,根據用戶的相關定義,我們定義一個實體類,用來放置獲取回來的用戶信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
/// <summary> /// 高級接口獲取的用戶信息。 /// 在關注者與公眾號產生消息交互后,公眾號可獲得關注者的openid /// (加密后的微信號,每個用戶對每個公眾號的openid是唯一的。對于不同公眾號,同一用戶的openid不同)。 /// 公眾號可通過本接口來根據openid獲取用戶基本信息,包括昵稱、頭像、性別、所在城市、語言和關注時間。 /// </summary> public class userjson : basejsonresult { /// <summary> /// 用戶是否訂閱該公眾號標識,值為0時,代表此用戶沒有關注該公眾號,拉取不到其余信息。 /// </summary> public int subscribe { get ; set ; } /// <summary> /// 用戶的標識,對當前公眾號唯一 /// </summary> public string openid { get ; set ; } /// <summary> /// 用戶的昵稱 /// </summary> public string nickname { get ; set ; } /// <summary> /// 用戶的性別,值為1時是男性,值為2時是女性,值為0時是未知 /// </summary> public int sex { get ; set ; } /// <summary> /// 用戶的語言,簡體中文為zh_cn /// </summary> public string language { get ; set ; } /// <summary> /// 用戶所在城市 /// </summary> public string city { get ; set ; } /// <summary> /// 用戶所在省份 /// </summary> public string province { get ; set ; } /// <summary> /// 用戶所在國家 /// </summary> public string country { get ; set ; } /// <summary> /// 用戶頭像,最后一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空 /// </summary> public string headimgurl { get ; set ; } /// <summary> /// 用戶關注時間,為時間戳。如果用戶曾多次關注,則取最后關注時間 /// </summary> public long subscribe_time { get ; set ; } } |
根據分組信息定義,我們定義一個分組的實體類信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/// <summary> /// 分組信息 /// </summary> public class groupjson : basejsonresult { /// <summary> /// 分組id,由微信分配 /// </summary> public int id { get ; set ; } /// <summary> /// 分組名字,utf8編碼 /// </summary> public string name { get ; set ; } } |
2、獲取aip調用者的的token
在做微信api的開發,很多時候,我們都需要傳入一個accesstoken,這個就是區分調用者和記錄會話信息的字符串,因此,在學習所有api開發之前,我們需要很好理解這個訪問控制參數。
這個對象的定義,我們可以從微信的api說明中了解。
access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。正常情況下access_token有效期為7200秒,重復獲取將導致上次獲取的access_token失效。由于獲取access_token的api調用次數非常有限,建議開發者全局存儲與更新access_token,頻繁刷新access_token會導致api調用受限,影響自身業務。
根據上面的說明定義,我們可以看到,它是一個和身份,以及會話時間有關的一個參數,而且它的產生次數有限制,因此要求我們需要對它進行緩存并重復利用,在會話到期之前,我們應該盡可能重用這個參數,避免反復請求,增加服務器壓力,以及調用的時間。
我定義了一個方法,用來構造生成相關的access token,而且它具有緩存的功能,但具體如何緩存及使用,對我api的調用是透明的,我們只要用的時候,就對它調用就是了。
1
2
3
4
5
|
/// 獲取憑證接口 /// </summary> /// <param name="appid">第三方用戶唯一憑證</param> /// <param name="secret">第三方用戶唯一憑證密鑰,既appsecret</param> string getaccesstoken( string appid, string secret); |
緩存主要是基于.net4增加的類庫memorycache,這個是一個非常不錯的緩存類。
我的獲取accesstoken的操作實現代碼如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/// <summary> /// 獲取每次操作微信api的token訪問令牌 /// </summary> /// <param name="appid">應用id</param> /// <param name="secret">開發者憑據</param> /// <returns></returns> public string getaccesstoken( string appid, string secret) { //正常情況下access_token有效期為7200秒,這里使用緩存設置短于這個時間即可 string access_token = memorycachehelper.getcacheitem< string >( "access_token" , delegate () { string grant_type = "client_credential" ; var url = string .format( "https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}" , grant_type, appid, secret); httphelper helper = new httphelper(); string result = helper.gethtml(url); string regex = "\"access_token\":\"(?<token>.*?)\"" ; string token = cregex.gettext(result, regex, "token" ); return token; }, new timespan(0, 0, 7000) //7000秒過期 ); return access_token; } |
由于我們知道,accesstoken默認是7200秒過期,因此在這個時間段里面,我們盡可能使用緩存來記錄它的值,如果超過了這個時間,我們調用這個方法的時候,它會自動重新獲取一個新的值給我們了。
3、獲取關注用戶列表
獲取關注用戶列表,一次拉取api調用,最多拉取10000個關注者的openid,可以通過多次拉取的方式來滿足需求。微信的接口定義如下所示。
http請求方式: get(請使用https協議)
https://api.weixin.qq.com/cgi-bin/user/get?access_token=access_token&next_openid=next_openid
這個接口返回的數據是
1
|
{ "total" :2, "count" :2, "data" :{ "openid" :[ "" , "openid1" , "openid2" ]}, "next_openid" : "next_openid" } |
根據返回的json數據定義,我們還需要定義兩個實體類,用來存放返回的結果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
/// <summary> /// 獲取關注用戶列表的json結果 /// </summary> public class userlistjsonresult : basejsonresult { /// <summary> /// 關注該公眾賬號的總用戶數 /// </summary> public int total { get ; set ; } /// <summary> /// 拉取的openid個數,最大值為10000 /// </summary> public int count { get ; set ; } /// <summary> /// 列表數據,openid的列表 /// </summary> public openidlistdata data { get ; set ; } /// <summary> /// 拉取列表的后一個用戶的openid /// </summary> public string next_openid { get ; set ; } } /// <summary> /// 列表數據,openid的列表 /// </summary> public class openidlistdata { /// <summary> /// openid的列表 /// </summary> public list< string > openid { get ; set ; } } |
為了獲取相關的用戶信息,我定義了一個接口,用來獲取用戶的信息,接口定義如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/// <summary> /// 微信用戶管理的api接口 /// </summary> public interface iuserapi { /// <summary> /// 獲取關注用戶列表 /// </summary> /// <param name="accesstoken">調用接口憑證</param> /// <param name="nextopenid">第一個拉取的openid,不填默認從頭開始拉取</param> /// <returns></returns> list< string > getuserlist( string accesstoken, string nextopenid = null ); /// <summary> /// 獲取用戶基本信息 /// </summary> /// <param name="accesstoken">調用接口憑證</param> /// <param name="openid">普通用戶的標識,對當前公眾號唯一</param> /// <param name="lang">返回國家地區語言版本,zh_cn 簡體,zh_tw 繁體,en 英語</param> userjson getuserdetail( string accesstoken, string openid, language lang = language.zh_cn); |
然后在實現類里面,我們分別對上面兩個接口進行實現,獲取用戶列表信息如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/// <summary> /// 獲取關注用戶列表 /// </summary> /// <param name="accesstoken">調用接口憑證</param> /// <param name="nextopenid">第一個拉取的openid,不填默認從頭開始拉取</param> /// <returns></returns> public list< string > getuserlist( string accesstoken, string nextopenid = null ) { list< string > list = new list< string >(); string url = string .format( "https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}" , accesstoken); if (! string .isnullorempty(nextopenid)) { url += "&next_openid=" + nextopenid; } userlistjsonresult result = jsonhelper<userlistjsonresult>.convertjson(url); if (result != null && result.data != null ) { list.addrange(result.data.openid); } return list; } |
我們看到,轉換的邏輯已經放到了jsonhelper里面去了,這個輔助類里面分別對數值進行了獲取內容,驗證返回值,然后轉換正確實體類幾個部分的操作。
獲取內容,通過輔助類httphelper進行,這個在我的公用類庫里面,里面的邏輯主要就是通過httprequest進行數據的獲取操作,不在贅述。
1
2
|
httphelper helper = new httphelper(); string content = helper.gethtml(url); |
由于返回的內容,我們需要判斷它是否正確返回所需的結果,如果沒有,拋出自定義的相關異常,方便處理,具體如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/// <summary> /// 檢查返回的記錄,如果返回沒有錯誤,或者結果提示成功,則不拋出異常 /// </summary> /// <param name="content">返回的結果</param> /// <returns></returns> private static bool verifyerrorcode( string content) { if (content.contains( "errcode" )) { errorjsonresult errorresult = jsonconvert.deserializeobject<errorjsonresult>(content); //非成功操作才記錄異常,因為有些操作是返回正常的結果({"errcode": 0, "errmsg": "ok"}) if (errorresult != null && errorresult.errcode != returncode.請求成功) { string error = string .format( "微信請求發生錯誤!錯誤代碼:{0},說明:{1}" , ( int )errorresult.errcode, errorresult.errmsg); logtexthelper.error(errorresult); throw new weixinexception(error); //拋出錯誤 } } return true ; } |
然后轉換為相應的格式,就是通過json.net的類庫進行轉換。
1
2
|
t result = jsonconvert.deserializeobject<t>(content); return result; |
這樣我們就可以在convertjson函數實體里面,完整的進行處理和轉換了,轉換完整的函數代碼如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
/// <summary> /// json字符串操作輔助類 /// </summary> public class jsonhelper<t> where t : class , new () { /// <summary> /// 檢查返回的記錄,如果返回沒有錯誤,或者結果提示成功,則不拋出異常 /// </summary> /// <param name="content">返回的結果</param> /// <returns></returns> private static bool verifyerrorcode( string content) { if (content.contains( "errcode" )) { errorjsonresult errorresult = jsonconvert.deserializeobject<errorjsonresult>(content); //非成功操作才記錄異常,因為有些操作是返回正常的結果({"errcode": 0, "errmsg": "ok"}) if (errorresult != null && errorresult.errcode != returncode.請求成功) { string error = string .format( "微信請求發生錯誤!錯誤代碼:{0},說明:{1}" , ( int )errorresult.errcode, errorresult.errmsg); logtexthelper.error(errorresult); throw new weixinexception(error); //拋出錯誤 } } return true ; } /// <summary> /// 轉換json字符串到具體的對象 /// </summary> /// <param name="url">返回json數據的鏈接地址</param> /// <returns></returns> public static t convertjson( string url) { httphelper helper = new httphelper(); string content = helper.gethtml(url); verifyerrorcode(content); t result = jsonconvert.deserializeobject<t>(content); return result; } } |
調用這個api的界面層代碼如下所示(測試代碼)
1
2
|
iuserapi userbll = new userapi(); list< string > userlist = userbll.getuserlist(token) |
4、獲取用戶詳細信息
上面的獲取列表操作,相對比較簡單,而且不用post任何數據,因此通過get協議就能獲取到所需的數據。
本小節繼續介紹獲取用戶詳細信息的操作,這個操作也是通過get協議就可以完成的。
這個api的調用定義如下所示:
http請求方式: get
https://api.weixin.qq.com/cgi-bin/user/info?access_token=access_token&openid=openid&lang=zh_cn
通過傳入一個openid,我們就能很好獲取到用戶的相關信息了。
前面小節我們已經定義了它的接口,說明了傳入及返回值,根據定義,它的實現函數如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/// <summary> /// 獲取用戶基本信息 /// </summary> /// <param name="accesstoken">調用接口憑證</param> /// <param name="openid">普通用戶的標識,對當前公眾號唯一</param> /// <param name="lang">返回國家地區語言版本,zh_cn 簡體,zh_tw 繁體,en 英語</param> public userjson getuserdetail( string accesstoken, string openid, language lang = language.zh_cn) { string url = string .format( "https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang={2}" , accesstoken, openid, lang.tostring()); userjson result = jsonhelper<userjson>.convertjson(url); return result; } |
最后,我們結合獲取用戶列表和獲取用戶詳細信息的兩個api,我們看看調用的代碼(測試代碼)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private void btngetusers_click( object sender, eventargs e) { iuserapi userbll = new userapi(); list< string > userlist = userbll.getuserlist(token); foreach ( string openid in userlist) { userjson userinfo = userbll.getuserdetail(token, openid); if (userinfo != null ) { string tips = string .format( "{0}:{1}" , userinfo.nickname, userinfo.openid); console.writeline(tips); } } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://wuhuacong.cnblogs.com/p/3695213.html