In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Php Wechat public account development easy to encounter what are the holes, I believe that many inexperienced people do not know what to do, so this article summarizes the causes of the problem and solutions, through this article I hope you can solve this problem.
The menu reply needs to deal with the XML file. According to the XML file returned by Wechat, we can get the unique identity of each Wechat user relative to the Wechat official account. The mechanism of Wechat public platform will simply be that we output xml files in a fixed format, and then Wechat APP is responsible for parsing, getting the information we want, and then processing the information uniformly.
Pit 6, if you look at Wechat documents, it will definitely kill you, pictured above. Here the ToUserName and FromUserName must be fucking clear, remember, do not write backwards, users for Wechat is A → B, then Wechat for users is the opposite, it seems that now should be clear.
/ receive XML messages sent by Wechat and parse / private void ReceiveXml () {try {Stream requestStream = System.Web.HttpContext.Current.Request.InputStream; byte [] requestByte = new byte [requestStream.Length]; requestStream.Read (requestByte, 0, (int) requestStream.Length); string requestStr = Encoding.UTF8.GetString (requestByte); if (! string.IsNullOrEmpty (requestStr)) {/ / Encapsulation request class XmlDocument requestDocXml = new XmlDocument () RequestDocXml.LoadXml (requestStr); XmlElement rootElement = requestDocXml.DocumentElement; WxXmlModel WxXmlModel = new WxXmlModel (); if (rootElement! = null) {WxXmlModel.ToUserName = rootElement.SelectSingleNode ("ToUserName") = = null? "": rootElement.SelectSingleNode ("ToUserName"). InnerText; WxXmlModel.FromUserName = rootElement.SelectSingleNode ("FromUserName") = = null? "": rootElement.SelectSingleNode ("FromUserName"). InnerText; WxXmlModel.CreateTime = rootElement.SelectSingleNode ("CreateTime") = = null? "": rootElement.SelectSingleNode ("CreateTime"). InnerText WxXmlModel.MsgType = rootElement.SelectSingleNode ("MsgType") = = null? "": rootElement.SelectSingleNode ("MsgType"). InnerText; switch (WxXmlModel.MsgType) {case "text": / / text WxXmlModel.Content = rootElement.SelectSingleNode ("Content") = = null? "": rootElement.SelectSingleNode ("Content"). InnerText; break; case "image": / / Picture WxXmlModel.PicUrl = rootElement.SelectSingleNode ("PicUrl") = null? "": rootElement.SelectSingleNode ("PicUrl"). InnerText Break; case "event": / / event WxXmlModel.Event = rootElement.SelectSingleNode ("Event") = = null? "": rootElement.SelectSingleNode ("Event"). InnerText; if (WxXmlModel.Event! = "TEMPLATESENDJOBFINISH") / / interest type {WxXmlModel.EventKey = rootElement.SelectSingleNode ("EventKey") = = null? "": rootElement.SelectSingleNode ("EventKey"). InnerText;} break; default: break;} ResponseXML (WxXmlModel) / / reply message} catch (Exception ee) {/ / record error log}} / private void ResponseXML (WxXmlModel WxXmlModel) {string XML = "; switch (WxXmlModel.MsgType) {case" text ": / / text reply var info = oauth.GetUserInfo (Tools.WA_GetAccess_Token.IsExistAccess_Token (), WxXmlModel.FromUserName); Tools.WAEntity.OAuthUser user = Tools.JsonHelper.ParseFromJson (info) Var content = WxXmlModel.Content.ToUpper (); string NcbActUrl = ConfigurationManager.AppSettings ["NcbActUrl"]; string appid = ConfigurationManager.AppSettings ["AppID"]; if (content.Contains ("T")) / / accepted text if it contains T {/ / Business processing} else {XML = ResponseMessage.ReText (WxXmlModel.FromUserName, WxXmlModel.ToUserName, "/: welcome to rose Farm big data! /: rose ");} break; case" event ": switch (WxXmlModel.Event.ToLower ()) {case" subscribe ": if (string.IsNullOrEmpty (WxXmlModel.EventKey)) {XML = ResponseMessage.ReText (WxXmlModel.FromUserName, WxXmlModel.ToUserName," follow success! /: rose ");} else {XML = ResponseMessage.SubScanQrcode (WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey); / / scan with parameter QR code follow first and then push event} break; case" scan ": XML = ResponseMessage.ScanQrcode (WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey); / / scan with parameter QR code has paid attention to direct push event break Case "click": / / handle click event if (WxXmlModel.EventKey = = "p1") {/ / own business logic} else {/ / own business logic} break; case "unsubscribe": / / unfollow break;} break; default:// default reply break;} Response.Write (XML); / / output the organization's XML information}
This is the information processing of the menu, and people who don't know the truth seem to ask how much meaning the so-called ResponseMessage actually means. OK, I can no longer complain about the Wechat public platform that I have developed in the past three days.
Public class ResponseMessage {# region received type / received text / public static string GetTextTest (string FromUserName, string ToUserName, string Content, string key) {CommonMethod.WriteTxt (Content); / / received text message string XML = ""; switch (Content) {case "keyword": XML = ReText (FromUserName, ToUserName, "keyword reply Test-Xingnong Fenghua:" + key) Break; case "single picture and text": XML = ReArticle (FromUserName, ToUserName, "test title", "test details-Xingnong Fenghua:" + key, "http://www.xnfhtech.com/templets/boze/images/20120130083143544.gif"," http://www.xnfhtech.com/"); break; default: XML = ReText (FromUserName, ToUserName, "no corresponding keyword-Xingnong Fenghua:" + key); break;} return XML } / public static string SubScanQrcode (string FromUserName, string ToUserName, string EventKey) {return ";} / public static string ScanQrcode (string FromUserName, string ToUserName, string EventKey) {return" } # endregion # region reply method / reply text / to whom (openid) / / from whom (public account ID) / / reply type text / patchwork of XML public static string ReText (string FromUserName, string ToUserName, string Content) {string XML = "" / / to whom (openid), from whom (public account ID) XML + = "" + CommonMethod.ConvertDateTimeInt (DateTime.Now) + ""; / / reply timestamp XML + = ""; / / reply type text XML + = "0"; / / when the reply content FuncFlag is set to 1, the message received by the automatic star mark is suitable for activity statistics using return XML. } / reply single picture and text / to whom (openid) / / from whom (public account ID) / / title / / details / / picture address / / address / patchwork of XML public static string ReArticle (string FromUserName, string ToUserName, string Title, string Description, string PicUrl, string Url) {string XML = "" / / to whom (openid), from whom (public account ID) XML + = "" + CommonMethod.ConvertDateTimeInt (DateTime.Now) + ""; / / reply timestamp XML + = "1"; XML + = ""; XML + = "0"; return XML } / multiple text reply / to whom (openid) / / from whom (public account ID) / number of graphics and text / public static string ReArticle (string FromUserName, string ToUserName, int ArticleCount, System.Data.DataTable dtArticle) {string XML = ""; / / to whom (openid), from whom (public account ID) XML + = "+ CommonMethod.ConvertDateTimeInt (DateTime.Now) +" / / reply timestamp XML + = "" + ArticleCount + ""; foreach (System.Data.DataRow Item in dtArticle.Rows) {XML + = "";} XML + = "0"; return XML;} # endregion}
Does OK, with its own logic code, perfectly implement the reply?
Pit 7, I really don't want to count anymore. Are you sure this reply is OK? To tell you the truth, the baby is not sure, because you know where to call it after you have written it, my dear, Nima, it is safest to add the reply as soon as the server is verified. I've lost my integrity.
What are we going to say next? let's talk about getting user information, because we are generally based on H5 pages. So, we need to use what we configured before.
This thing, in fact, compared with the previous at least a lot less, really, the baby will not say that he is a pit for the time being. Let's go to the code.
/ / Wechat web page authorization 2.0public class Oauth3 {JavaScriptSerializer Jss = new JavaScriptSerializer () Public Oauth3 () {} / A pair of pages whether to use authorization / Wechat application id / callback page / application authorization scope snsapi_userinfo (do not pop up authorization page, jump directly, only get user openid), snsapi_userinfo (pop-up authorization page, you can get nickname, gender, location through openid. And, even without paying attention, the information can be obtained as long as the user is authorized) / / the authorized address public string GetCodeUrl (string Appid, string redirect_uri, string scope) {return string.Format ("https://open.weixin.qq.com/connect/oauth3/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state=STATE#wechat_redirect", Appid, redirect_uri, scope) } / whether a pair of pages should use the authorization snsapi_userinfo / Wechat application id / callback page / application authorization scope snsapi_userinfo (do not pop up the authorization page, jump directly, only the user openid can be obtained), snsapi_userinfo (pop-up authorization page, you can get nickname, gender, and location through openid. And, even without paying attention, the information can be obtained as long as the user is authorized) / / the authorized address public string GetCodeUrl (string Appid, string redirect_uri, string scope,string state) {return string.Format ("https://open.weixin.qq.com/connect/oauth3/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state={3}#wechat_redirect", Appid, redirect_uri, scope, state) } / exchange code for openid. This method generally uses the code parameter / Wechat user's unique ID openid public string CodeGetOpenid (string Appid, string Appsecret) in the callback page without getting the user nickname. String Code) {string url = string.Format ("https://api.weixin.qq.com/sns/oauth3/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", Appid, Appsecret, Code) String ReText = CommonMethod.WebRequestPostOrGet (url, "); / / post/get method to get information Dictionary DicText = (Dictionary) Jss.DeserializeObject (ReText); if (! DicText.ContainsKey (" openid ")) return"; return DicText [" openid "] .ToString () } / use code to get user information (including those of non-followers) / / call back the code parameter / to get user information (json format) public string GetUserInfo (string Appid, string Appsecret) String Code) {string url = string.Format ("https://api.weixin.qq.com/sns/oauth3/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", Appid, Appsecret, Code) String ReText = CommonMethod.WebRequestPostOrGet (url, "); / / post/get method to get information Dictionary DicText = (Dictionary) Jss.DeserializeObject (ReText); if (! DicText.ContainsKey (" openid ")) {log.Error (" failed to get openid, error code: "+ DicText [" errcode "] .ToString ()); return" } else {return CommonMethod.WebRequestPostOrGet ("https://api.weixin.qq.com/sns/userinfo?access_token=" + DicText [" access_token "] +" & openid= "+ DicText [" openid "] +" & lang=zh_CN ",") }} / obtain user information through openId / public string GetUserInfo (string accesstoken, string openid) {string url = string.Format ("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", accesstoken, openid); return CommonMethod.WebRequestPostOrGet (url,"); / / post/get method to obtain information}
When we need to call, we can directly use the method inside to obtain the Wechat web page authorization. For example, to obtain the authorization for View B under the A controller, and to obtain the relevant information of the user, then we can directly call GetCodeUrl (appid, "http://" + Url +" / A snsapi_userinfo B "," snsapi_userinfo ").
I'd better complain here.
The eighth pit, Wechat menu JSON url splicing, which is not in front of the js verification, so, damn it, or obediently add http://.
However, after the authorization here, because we have to use a lot of user information, this is the problem of passing values on the H5 page. I used Session in the project to write a common method directly. If Session has a value, then take a value directly. For some of the things in it, I would like to make it clear that not all the code has to be posted. The code on my side is only what I personally think needs to be posted. So there may be some methods that you can't see. If necessary, you can leave a message for the baby. Thank you.
Public string getSession () {log.Error ("GetSession"); string oauthStr = ""; try {if (Session! = null & & (Session ["oauthStr"] = = null | | string.IsNullOrEmpty (Session ["oauthStr"]. ToString ()) {if (! string.IsNullOrEmpty (Request.QueryString ["code"])) {Oauth3 oauth = new Oauth3 (); string code = Convert.ToString (Request ["code"]) OauthStr = oauth.GetUserInfo (ConfigurationManager.AppSettings ["AppID"], ConfigurationManager.AppSettings ["AppSecret"], code); Session ["oauthStr"] = oauthStr; Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser (); oAuthUser = Tools.JsonHelper.ParseFromJson (oauthStr);} return oauthStr;} else {Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser (); oAuthUser = Tools.JsonHelper.ParseFromJson (Session ["oauthStr"]. ToString ()); return Session ["oauthStr"]. ToString () }} catch (Exception e) {log.Error (e.ToString ()); return oauthStr;};}
Then every time I come across a page that needs to get information, I usually call this.
Basically what's left is the business logic we have to deal with, so let's keep talking about it.
Pit 9, Wechat upload pictures, definitely not just yourself. I really believe this baby, whether you believe it or not. Fucking pictures cannot be uploaded in a loop on for. Of course, this is limited to the Apple model, and there is no problem with the big Android.
I mentioned the issue of JS security verification, here is to call these verifications, request some permissions, and then get image information and so on.
Don't worry, the baby is talking in the picture above now, and there is no picture of a little brother.
Let's go back and look at the code.
Let's start with someone who handles Json.
Public class JsApi {JavaScriptSerializer Jss = new JavaScriptSerializer (); public JsApi () {} const string URL_FORMAT_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi"; # region verify JsApi permission configuration / get the array of JsApi permission configuration / apply four parameters in id / key / json format public string GetJsApiInfo (string Appid, string Appsecret) {string jsapi_ticket = "" / / ticket cache 7200 seconds if (System.Web.HttpContext.Current.Session ["jsapi_ticket"] = = null) {string ticketurl = string.Format (URL_FORMAT_TICKET, BasicApi.GetAccessToken (Appid, Appsecret)); / / "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + GetAccessToken (Appid, Appsecret) +" & type=jsapi "jsapi_ticket = CommonMethod.WebRequestPostOrGet (ticketurl,") / BasicApi.GetTokenSession System.Web.HttpContext.Current.Session ["jsapi_ticket"] = jsapi_ticket; System.Web.HttpContext.Current.Session.Timeout = 7200; BasicApi.WriteTxt ("jsapi_ticket1:" + jsapi_ticket);} else {jsapi_ticket = System.Web.HttpContext.Current.Session ["jsapi_ticket"] .ToString (); BasicApi.WriteTxt ("jsapi_ticket2:" + jsapi_ticket);} Dictionary respDic = (Dictionary) Jss.DeserializeObject (jsapi_ticket) Jsapi_ticket = respDic ["ticket"] .ToString (); / get ticket string timestamp = CommonMethod.ConvertDateTimeInt (DateTime.Now) .ToString (); / / timestamp of generating signature string nonceStr = CommonMethod.GetRandCode (16); / / random string of generating signature string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.ToString (); / / current address BasicApi.WriteTxt ("url:" + url) String [] ArrayList = {"jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonceStr, "url=" + url}; Array.Sort (ArrayList); string signature = string.Join ("&", ArrayList); signature = FormsAuthentication.HashPasswordForStoringInConfigFile (signature, "SHA1"). ToLower () String r = "{\" appId\ ":\" + Appid + "\",\ "timestamp\": "+ timestamp +",\ "nonceStr\":\ "" + nonceStr + "\",\ "signature\":\ "+ signature +"\ ",\" jsApiList\ ": [\" chooseImage\ ",\" previewImage\ ",\" uploadImage\ ",\" downloadImage\ ",\" scanQRCode\ ",\" onMenuShareQQ\ "]}" BasicApi.WriteTxt ("r:" + r.Replace (",")); return r.Replace (",");}}
Then look at the specific call.
The background code is actually very simple, directly output the configuration file, and then the foreground js can be called directly.
JsApi jsApi = new JsApi (); string config = jsApi.GetJsApiInfo (appId, appSecret); ViewBag.config = config
Foreground code, in fact, is not difficult, this has an official example.
Wx.config (@ Html.Raw (ViewBag.config)) / / Wechat configuration file wx.ready (function () {$("# avatar") .click (function () {wx.chooseImage ({count: 1, / / the number of images defaults to 9 sizeType: ['compressed'], / / you can specify whether it is the original image or a compressed image. By default, both have' original', sourceType: ['album',' camera'], / / you can specify whether the source is a photo album or a camera By default, both have success: function (res) {var localIds = res.localIds / / returns the local ID list of the selected photo. LocalId can display the picture wx.uploadImage as the src attribute of the img tag ({localId:''+ localIds, isShowProgressTips: 1, success: function (res) {serverId = res.serverId; getWxPhoto (serverId);}});}) Wx.error (function (res) {alert ("Interface verification failed, details:\ n" + JSON.stringify (res)); var types = 1; function getWxPhoto (mediaId) {$.ajax ({async: false, type: "post", url: "/ ActivityRegistration/DownloadWxPhoto", / / own processing method data: {mediaId: mediaId, types: types}, success: function (data) {$("# imageico") .val (data.result) $("# hed_pic"). Attr ('src', ".." + data.result); $("# hed_pic"). Attr (' alt', "avatarImg");});}
OK, the background method is actually very simple, is a binary file processing, no, simple balls, damn it, because of the path problem, cheated the baby for an hour, damn it. It is also suggested here that after the Wechat picture download is completed, then load the picture to the foreground, ensure that each picture is loaded and upload the picture in the background.
/ / download multimedia file / official account / / Media ID/// returns whether the download was successful / / the added picture type / returns the multimedia file data; if the download fails, return null. Public JsonResult DownloadWxPhoto (string mediaId, int types) {ErrorMessage errorMessage; string access_token = BasicApi.GetAccessToken (ConfigurationManager.AppSettings ["AppID"], ConfigurationManager.AppSettings ["AppSecret"]); byte [] data = MediaHelper.Download (access_token, mediaId, out errorMessage); string files = String.Empty, fileName = String.Empty; files = Server.MapPath ("~ / Wxinphoto/"); if (! Directory.Exists (files)) {Directory.CreateDirectory (files);} fileName = files + DateTime.Now.Ticks + ".jpg" If (data! = null) {bool flag = writeFile (data, fileName); if (flag) {errorMessage = new ErrorMessage (ErrorMessage.SuccessCode, "multimedia file downloaded successfully.") ;} else {errorMessage = new ErrorMessage (ErrorMessage.ExceptionCode, "failed to download multimedia file from Wechat server.") ;} else errorMessage = new ErrorMessage (ErrorMessage.ExceptionCode, "failed to download multimedia file from Wechat server.") ; return Json (new {result = "/" + urlconvertor (fileName), errorMessage = errorMessage});} / read filename to byte [] private byte [] ReadFile (string fileName) {FileStream pFileStream = null; byte [] pReadByte = new byte [0]; try {pFileStream = new FileStream (fileName, FileMode.Open, FileAccess.Read); BinaryReader r = new BinaryReader (pFileStream); r.BaseStream.Seek (0, SeekOrigin.Begin); / / set the file pointer to the file pReadByte = r.ReadBytes ((int) r.BaseStream.Length); return pReadByte } catch {return pReadByte;} finally {if (pFileStream! = null) pFileStream.Close ();}} / write byte [] to fileNameprivate bool writeFile (byte [] pReadByte, string fileName) {FileStream pFileStream = null; try {pFileStream = new FileStream (fileName, FileMode.OpenOrCreate); pFileStream.Write (pReadByte, 0, pReadByte.Length);} catch {return false;} finally {if (pFileStream! = null) pFileStream.Close ();} return true } / determine whether the destination byte array is at the beginning of the source byte array / source byte array / destination byte array / / return whether the destination byte array is at the beginning of the source byte array private bool StartsWithBytes (byte [] source, byte [] target) {if (source = = null & & target = = null) return true; if (source = = null & & target! = null | source! = null & target = null return false) If (source.Length
< target.Length) return false; bool startsWith = true; for (int i = 0; i < target.Length; i++) { if (source[i] != target[i]) { startsWith = false; break; } } return startsWith;} 是不是以为这就算完事了,我的乖乖,头像上传了,微信摄像头也特么该调用的调用了,宝宝好幸福,宝宝也是牛人一个了,记住前面的东东,宝宝还没有说坑呢。 来重复我们的第九个坑,特么的,你JS写个for循环要是能循环把图片上传到后台,宝宝也服气,真的,宝宝服气。 直接说吧,最后我自己想了下,也和队友讨论了下,可能是因为微信有什么验证,导致之后一张图片上传成功之后,才能进行一张,但是我们Iphone就是特么的特例,大Android没用问题的,就是Iphone有了问题,而且问题不小,上传四张图片吧,老特么是最后一张,最后,找到了万能的网友,感谢你,不过宝宝已经忘记了在哪里找到的了,尴尬了。。。。。。。。。。。 var types = 2; var urlList=""; var i = 0; function up(resurl) { if (i < resurl.localIds.length) { // 上传照片resu.localIds[i] wx.uploadImage({ localId: '' + resurl.localIds[i], isShowProgressTips: 1, success: function (res) { // alert("res.serverId:" + res.serverId); mediaId = res.serverId; $.ajax({ async: false, type: "post", url: "/ActivityRegistration/DownloadWxPhoto", data: { mediaId: mediaId, types: types }, success: function (data) { $("#picPath").append('); $("# picture" + I) .attr ('src', data.result); $("# picPath"). Append ('); iTunes; if (I = = resurl.localIds.length-1) {$("# picPath"). Append ('
');} up (resurl);}});}});} else {I = 0;}} / / upload picture wx.config (@ Html.Raw (ViewBag.config)) Wx.ready (function () {$("# picPath") .click (function () {wx.chooseImage ({count: 3, / / default 9 sizeType: ['compressed'], / / you can specify whether it is the original image or a compressed image. By default, both have' original', sourceType: ['album',' camera'], / / you can specify whether the source is a photo album or a camera By default, both have success: function (resu) {var localIds = resu.localIds / / returns the local ID list of selected photos. LocalId can display the picture if (localIds.indexOf ("wxlocalresource")! =-1) {localIds = localIds.replace ("wxlocalresource", "wxLocalResource");} @ (index + = 1) if (localIds! ='') {$("# picPath") .html (""); var sear = new RegExp (',') as the src attribute of the img tag. If (sear.test (localIds)) {up (resu);} else {$("# picPath") .append ('
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.