English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
이전 글에서 웨이터 공공 계정의 몇 가지 문제점에 대해 이야기했습니다. 앞 다섯 가지는 메뉴에 대해 이야기했습니다. 저는 계속해서 더 이야기해야 합니다. 그러나 저의 아이가 제 아이를 아끼는지 모르겠습니다. 아, 혼란스럽네요...
본론에 돌아와서, 다른 것들을 지적하지 않겠습니다. 이전 글에서 웨이터 메뉴에 대해 이야기했습니다. 그렇다면 지금은 메뉴 응답 등에 대해 이야기해보죠.
메뉴 응답은 XML 파일을 처리해야 하는 것입니다.,我们根据微信返回的XML文件,可以得到每个微信用户相对于微信公众号的唯一标识。微信公众平台的机制简单的将就是我们自己输出固定格式的xml文件,然后微信APP负责解析,得到我们想要的信息,然后对信息统一处理。
第六坑,如果你看微信文档,那么,绝对坑死你,上图。这里的ToUserName和FromUserName一定特么的要分清楚了,记住,千万不要写反了,用户对于微信而言是A→B,那么微信对于用户就是反着来的,貌似现在应该说清楚了。
/// <summary> /// 接收微信发送的XML消息并且解析 /// </summary> 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)) { //封装请求类 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;63; "" : rootElement.SelectSingleNode("ToUserName").InnerText; WxXmlModel.FromUserName = rootElement.SelectSingleNode("FromUserName") == null ? "" : rootElement.SelectSingleNode("ToUserName").InnerText;63; "" : 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"://텍스트 WxXmlModel.Content = rootElement.SelectSingleNode("Content") == null ? "" : rootElement.SelectSingleNode("Content").InnerText; break; case "image"://이미지 WxXmlModel.PicUrl = rootElement.SelectSingleNode("PicUrl") == null ? "" : rootElement.SelectSingleNode("PicUrl").InnerText; break; case "event"://이벤트 WxXmlModel.Event = rootElement.SelectSingleNode("Event") == null ? "" : rootElement.SelectSingleNode("Event").InnerText; if (WxXmlModel.Event != "TEMPLATESENDJOBFINISH")//참여 유형 { WxXmlModel.EventKey = rootElement.SelectSingleNode("EventKey") == null ? "" : rootElement.SelectSingleNode("EventKey").InnerText; } break; default: break; } } ResponseXML(WxXmlModel);//응답 메시지 } } catch (Exception ee) { //에러 로그 기록 } } /// <summary> /// 응답 메시지 /// </summary> /// <param name="WxXmlModel"></param> private void ResponseXML(WxXmlModel WxXmlModel) { string XML = "; switch (WxXmlModel.MsgType) { case "text"://텍스트 응답 var info = oauth.GetUserInfo(Tools.WA_GetAccess_Token.IsExistAccess_Token(), WxXmlModel.FromUserName); Tools.WAEntity.OAuthUser user = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(info); var content = WxXmlModel.Content.ToUpper(); string NcbActUrl = ConfigurationManager.AppSettings["NcbActUrl"]; string appid = ConfigurationManager.AppSettings["AppID"]; if (content.Contains("T"))//받은 텍스트가 "T"를 포함하면 { //업무 처리 } else { XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "/:rose 농장 대시보드 환영합니다!/:rose"); } break; case "event": switch (WxXmlModel.Event.ToLower()) { case "subscribe": if (string.IsNullOrEmpty(WxXmlModel.EventKey)) { XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "关注成功!"/:rose"); } else { XML = ResponseMessage.SubScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//스캔된 파라미터 QR 코드를 먼저 구독하고 이벤트를 전송합니다 } break; case "scan": XML = ResponseMessage.ScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//미가입자가 파라미터를 포함한 QR 코드를 스캔했습니다. 직접 이벤트를 전달합니다 break; case "click"://단일 클릭 이벤트 처리 if (WxXmlModel.EventKey == "p1") { //자신의 비즈니스 로직 } else { //자신의 비즈니스 로직 } break; case "unsubscribe"://구독 취소 break; } break; default://기본 응답 break; } Response.Write(XML);//조직된 XML 정보를 출력합니다 }
이것은 메뉴 정보 처리입니다. 무지한 대중들이 그것이란 ResponseMessage가 정확히 어떤 의미를 가지는지 모릅니다. 좋아요, 이제 나는 이제 막 연구한 微信 공용 플랫폼의 것에 대해 더 이상 토로할 수 없습니다.
public class ResponseMessage { #region 받는 타입 /// <summary> /// 텍스트를 받습니다 /// </summary> /// <param name="FromUserName"></param> /// <param name="ToUserName"></param> /// <param name="Content"></param> /// <returns></returns> public static string GetTextTest(string FromUserName, string ToUserName, string Content, string key) { CommonMethod.WriteTxt(Content);//받은 텍스트 메시지 string XML = "; switch (Content) { case "키워드": XML = ReText(FromUserName, ToUserName, "키워드 응답 테스트 - 신농부채화:" + key); break; case "단일 이미지 텍스트": XML = ReArticle(FromUserName, ToUserName, "테스트 제목", "테스트 상세 - 신농부채화:" + key, "http://www.xnfhtech.com/templets/boze/images/20120130083143544.gif", "http://www.xnfhtech.com/"); break; default: XML = ReText(FromUserName, ToUserName, "무제목 키워드가 없음 - 신농부채화:" + key); break; } return XML; } /// <summary> /// 미가입자가 파라미터를 포함한 QR 코드를 스캔했습니다 /// </summary> /// <param name="FromUserName"></param> /// <param name="ToUserName"></param> /// <param name="EventKey"></param> /// <returns></returns> public static string SubScanQrcode(string FromUserName, string ToUserName, string EventKey) { return ""; } /// <summary> /// 이미 구독한 스캔된 파라미터 QR 코드 /// </summary> /// <param name="FromUserName"></param> /// <param name="ToUserName"></param> /// <param name="EventKey"></param> /// <returns></returns> public static string ScanQrcode(string FromUserName, string ToUserName, string EventKey) { return ""; } #endregion #region 回复方式 /// <summary> /// 回复文本 /// </summary> /// <param name="FromUserName">发送给谁(openid)</param> /// <param name="ToUserName">来自谁(公众账号ID)</param> /// <param name="Content">回复类型文本</param> /// <returns>拼凑的XML</returns> public static string ReText(string FromUserName, string ToUserName, string Content) { string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//보내는 사람(openid), 보내는 사람(공동 계정 ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//답변 시간 스탬프 XML += "<MsgType><![CDATA[text]]></MsgType>";//回复类型文本 XML += "<Content><![CDATA[" + Content + "]]></Content><FuncFlag>0</FuncFlag></xml>";//回复内容 FuncFlag设置为1的时候,自动星标刚才接收到的消息,适合活动统计使用 return XML; } /// <summary> /// 回复单图文 /// </summary> /// <param name="FromUserName">发送给谁(openid)</param> /// <param name="ToUserName">来自谁(公众账号ID)</param> /// <param name="Title">标题</param> /// <param name="Description">详情</param> /// <param name="PicUrl">图片地址</param> /// <param name="Url">地址</param> /// <returns>拼凑的XML</returns> public static string ReArticle(string FromUserName, string ToUserName, string Title, string Description, string PicUrl, string Url) { string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//보내는 사람(openid), 보내는 사람(공동 계정 ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//답변 시간 스탬프 XML += "<MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>1</ArticleCount><Articles>"; XML += "<item><Title><![CDATA[" + Title + "]]></Title><Description><![CDATA[" + Description + "]]></Description><PicUrl><![CDATA[" + PicUrl + "]]></PicUrl><Url><![CDATA[" + Url + "]]></Url></item>"; XML += "</Articles><FuncFlag>0</FuncFlag></xml>"; return XML; } /// <summary> /// 多图文回复 /// </summary> /// <param name="FromUserName">发送给谁(openid)</param> /// <param name="ToUserName">来自谁(公众账号ID)</param> /// <param name="ArticleCount">图文数量</param> /// <param name="dtArticle"></param> /// <returns></returns> public static string ReArticle(string FromUserName, string ToUserName, int ArticleCount, System.Data.DataTable dtArticle) { string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//보내는 사람(openid), 보내는 사람(공동 계정 ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//답변 시간 스탬프 XML += "<MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>" + ArticleCount + "</ArticleCount><Articles>"; foreach (System.Data.DataRow Item in dtArticle.Rows) { XML += "<item><Title><![CDATA[" + Item["Title"] + "]]></Title><Description><![CDATA[" + Item["Description"] + "]]></Description><PicUrl><![CDATA[" + Item["PicUrl"] + "]]></PicUrl><Url><![CDATA[" + Item["Url"] + "]]></Url></item>"; } XML += "</Articles><FuncFlag>0</FuncFlag></xml>"; return XML; } #endregion }
예, 자신의 로직 코드를 추가해 보세요. 답변이 완벽하게 구현되었는지요?
칠 번째 공간,제가 정말로 세기를 세우고 싶지 않습니다. 이 답변이 확정되었습니까? 정말로 말씀드리겠습니다, 맞벌이가 이렇게 썼다면 어디서 호출할 수 있을까요, 제 맞벌이, 나마, 서버 검증이 통과되면 답변을 추가하는 것이 가장 안전합니다. 저는 더 이상 도덕성이 없습니다.
接下来我们说什么呢,我们就说说获取用户信息这个东西吧,因为我们这些东西一般都是基于H5页面的。所以,就要用到之前我们配置的
这个东东,其实这个相对于前面的至少坑少了很多,真心的,宝宝就暂时不说他坑了。上个代码吧。
//微信网页授权2.0 public class Oauth2 { JavaScriptSerializer Jss = new JavaScriptSerializer(); public Oauth2() { } /// <summary> /// 对页面是否要用授权 /// </summary> /// <param name="Appid">微信应用id</param> /// <param name="redirect_uri">回调页面</param> /// <param name="scope">应用授权作用域snsapi_userinfo(不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)</param> /// <returns>授权地址</returns> public string GetCodeUrl(string Appid, string redirect_uri, string scope) { return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1&response_type=code&scope={2}"&state=STATE#wechat_redirect", Appid, redirect_uri, scope); } /// <summary> /// 对页面是否要用授权 /// </summary> /// <param name="Appid">微信应用id</param> /// <param name="redirect_uri">回调页面</param> /// <param name="scope">应用授权作用域snsapi_userinfo(不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)</param> /// <returns>授权地址</returns> public string GetCodeUrl(string Appid, string redirect_uri, string scope,string state) { return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1&response_type=code&scope={2&state={3}"#wechat_redirect", Appid, redirect_uri, scope, state); } /// <summary> /// 用code换取openid 此方法一般是不获取用户昵称时候使用 /// </summary> /// <param name="Appid"></param> /// <param name="Appsecret"></param> /// <param name="Code">리턴 페이지에 포함된 code 파라미터</param> /// <returns>微信用户唯一标识openid</returns> public string CodeGetOpenid(string Appid, string Appsecret, string Code) { string url = string.Format("https:",//api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1&code={2&grant_type=authorization_code", Appid, Appsecret, Code); string ReText = CommonMethod.WebRequestPostOrGet(url, "");//post/get 방법으로 정보를 가져옵니다 Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText); if (!DicText.ContainsKey("openid")) return ""; return DicText["openid"].ToString(); } /// <summary> ///code를 사용하여 사용자 정보를 가져옵니다 (비추천 사용자 포함) /// </summary> /// <param name="Appid"></param> /// <param name="Appsecret"></param> /// <param name="Code">리턴 페이지에 포함된 code 파라미터</param> /// <returns>사용자 정보를 가져오기 (json 형식)</returns> public string GetUserInfo(string Appid, string Appsecret, string Code) { string url = string.Format("https:",//api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1&code={2&grant_type=authorization_code", Appid, Appsecret, Code); string ReText = CommonMethod.WebRequestPostOrGet(url, "");//post/get 방법으로 정보를 가져옵니다 Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText); if (!DicText.ContainsKey("openid")) { log.Error("openid를 가져오는 데 실패했습니다, 오류 코드: ", + 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", ""); } } /// <summary> /// openId를 통해 사용자 정보를 가져옵니다 /// </summary> /// <param name="accesstoken"></param> /// <param name="openid"></param> /// <returns></returns> 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 방법으로 정보를 가져옵니다 } }
필요할 때 직접 내부 메서드를 사용하여 웨이브 오퍼라이즈를 가져올 수 있습니다. 예를 들어, A 컨트롤러의 B 뷰에서 권한을 가져오고 사용자의 관련 정보를 가져오려면 직접 호출할 수 있습니다. 예를 들어, GetCodeUrl(appid, "http://" + Url + "/A/"B", "snsapi_userinfo")
여기서는 비판하려고 합니다.
제8공간微信菜单JSON의 URL 결합, 앞에 js 검증을 추가했나요, so, 순순히 http:을 추가해야 합니다://
그런데 여기서 인증 후, 사용자의 많은 정보를 사용해야 하므로 이것은 H5페이지 값 전달 문제, 프로젝트 안에서 사용하는 것은 Session입니다. 공용 메서드를 작성하면 Session에 값이 있으면 값을 직접 가져옵니다. 그 안에 있는 일부 코드는 모두가 볼 수 없을 수도 있습니다. 필요하다면, 이 퍼즐을 댓글로 남겨 주세요. 감사합니다.
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"])) { Oauth2 oauth = new Oauth2(); 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<Tools.WAEntity.OAuthUser>(oauthStr); } return oauthStr; } else { Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser(); oAuthUser = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(Session["oauthStr"].ToString()); return Session["oauthStr"].ToString(); } } catch (Exception e) { log.Error(e.ToString()); return oauthStr; }; }
그런 다음 정보를 가져오는 페이지가 필요할 때마다, 저는 이를 호출하면 됩니다.
대부분은 우리가 처리해야 할 비즈니스 로직이 됩니다. 그럼 더 이상의 문제를 이야기해보겠습니다.
第九个坑,위ixin에 이미지를 업로드하는 것은 단순히 자신에게만 문제가 아닙니다. 이 아기는 진짜 믿었습니다. 어떤 사람이 믿든, 이미지는 for 반복으로 업로드할 수 없습니다. 물론, 이는 애플 모델에 한정되며, 대형 Android는 문제가 없습니다.
그 전에 말한 JS 보안 검증 문제, 여기서는 이러한 검증을 호출하고 필요한 권한을 요청하고 이미지 정보를 가져오는 것입니다.
안심하세요, 아기는 지금 이미지로 말하고 있습니다. 그런데 이미지가 없으면 아이들을 말할 수가 없습니다.....
그런 다음 코드를 되돌아보겠습니다.
Json 처리를 먼저 해보겠습니다
public class JsApi { JavaScriptSerializer Jss = new JavaScriptSerializer(); public JsApi() { } const string URL_FORMAT_TICKET = "https://api.weixin.qq.com/cgi-bin/티켓/getticket#63;access_token={0}&type=jsapi"; #region JsApi 권한 설정 확인 /// <summary> /// JsApi 권한 설정을 얻는 배열을 가져옵니다/네 가지 매개변수 /// </summary> /// <param name="Appid">애플리케이션 id</param> /// <param name="Appsecret">비밀키</param> /// <returns>json형식의 네 가지 매개변수</returns> public string GetJsApiInfo(string Appid, string Appsecret) { string jsapi_ticket = ""; //티켓 캐시7200초 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/티켓/getticket#63;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<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(jsapi_ticket); jsapi_ticket = respDic["ticket"].ToString();//티켓 가져오기 string timestamp = CommonMethod.ConvertDateTimeInt(DateTime.Now).ToString();//생성할 시그니처의 시간 티켓}} string nonceStr = CommonMethod.GetRandCode(16);//생성할签名的 랜덤 문자열 string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.ToString();//현재의 주소 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(" ", ""); } }
그런 다음 구체적인 호출을 확인하세요.
백그라운드 코드는 매우 간단합니다. 직접 설정 파일을 출력한 후, 프론트엔드 JS가 직접 호출할 수 있습니다.
JsApi jsApi = new JsApi(); string config = jsApi.GetJsApiInfo(appId, appSecret); ViewBag.config = config;
프론트엔드 코드는 어렵지 않습니다. 공식 예제가 있습니다.
<스크립트 타입="text"/제이스크립트> wx.config(@Html.Raw(ViewBag.config));//백엔드에서 전달된 웨이브 설정 파일 wx.ready(function () { $("#avatar").click(function () { wx.chooseImage({ count: 1, // 이미지 수 기본9 sizeType: ['compressed'], // 원본 이미지 또는 압축 이미지를 지정할 수 있습니다. 기본적으로 두 가지 모두 있습니다'original', sourceType: ['album', 'camera'], // 사진의 출처를 앨범이거나 카메라로 지정할 수 있습니다. 기본적으로 두 가지 모두 있습니다 success: function (res) { var localIds = res.localIds; // 반환된 선택 사진의 로컬 ID 목록, localId는 img 태그의 src 속성으로 이미지를 표시할 수 있습니다 wx.uploadImage({ localId: '' + localIds, isShowProgressTips: 1, success: function (res) { serverId = res.serverId; getWxPhoto(serverId); } }); } }); }); }); wx.error(function (res) { alert("인터페이스 검증 실패, 자세한 정보:\n" + JSON.stringify(res)); }); var types = 1; function getWxPhoto(mediaId) { $.ajax({ async: false, type: "post", url: "/ActivityRegistration/DownloadWxPhoto",//자신의 처리 메서드 data: { mediaId: mediaId, types: types }, success: function (data) { $("#imageico").val(data.result); $("#hed_pic").attr('src', ".." + data.result); $("#hed_pic").attr('alt', "avatarImg"); } }); } </스크립트>
좋아, 백엔드 메서드는 매우 간단합니다. 바이너리 파일 처리일 뿐입니다. 아니요, 간단하다고 생각하지 마세요. 특정 경로 문제로 인해 아기가 한 시간을 허비했습니다. 특정 경로 문제로 인해 아기가 한 시간을 허비했습니다. 여기서 제안하면, 웨이브 이미지 다운로드가 완료된 후 프론트엔드에 이미지를 로드하면 모든 이미지가 로드되었음을 보장하고, 백엔드의 이미지 업로드가 완료되었음을 보장하십시오.
/// <summary> /// 미디어 파일 다운로드 /// </summary> /// <param name="userName">공식 계정</param> /// <param name="mediaId">미디어 ID</param> /// <param name="data">다운로드 성공 여부를 반환</param> /// <param name="types">추가된 이미지 유형</param> /// <returns>반환된 멀티미디어 파일 데이터; 다운로드 실패 시 null을 반환.</returns> 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, "멀티미디어 파일 다운로드 성공."); } else { errorMessage = new ErrorMessage(ErrorMessage.ExceptionCode, "위챗 서버에서 멀티미디어 파일 다운로드 실패."); } } else errorMessage = new ErrorMessage(ErrorMessage.ExceptionCode, "위챗 서버에서 멀티미디어 파일 다운로드 실패."); return Json(new { result = "/" + urlconvertor(fileName), errorMessage = errorMessage }); } //filename을 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); //파일 포인터를 파일 시작 부분으로 설정합니다 pReadByte = r.ReadBytes((int)r.BaseStream.Length); return pReadByte; } catch { return pReadByte; } finally { if (pFileStream != null) pFileStream.Close(); } } //byte[]를 fileName에 쓰기 private 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; } /// <summary> /// 목표 바이트 배열이 원본 바이트 배열의 시작에 위치하는지�断定 /// </summary> /// <param name="source">원본 바이트 배열</param> /// <param name="target">목표 바이트 배열</param> /// <returns>목표 바이트 배열이 원본 바이트 배열의 시작에 위치하는지 여부를 반환</returns> 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; }
이게 끝인 줄 알았나요, 나의 소중한 분들아, 프로필 이미지를 업로드했지만, 위챗 카메라도 특별히 호출되었어요, 나는 정말 행복하다, 나도 마법사 같은 사람이 되었어요, 이전에 말한 것을 기억해, 나는 아직 문제를 말하지 않았어요.
나의 9번째 문제를 반복하자, JS에서 for 루프를 사용하여 이미지를 백엔드에 업로드할 수 있다면, 나도 절망스럽다, 정말로, 나는 절망스럽다.
직접 말하자, 마지막에 나 혼자 생각해보고, 팀원들과 논의해보니, 위챗에 어떤 인증이 있어서 그 후 한 장의 이미지를 업로드할 수 있게 되었지만, 우리 아이폰은 특이한 예외, 대형 안드로이드는 문제가 없지만, 아이폰은 문제가 크다, 네 장의 이미지를 업로드해보니, 마지막 장이 항상 그렇게 되더니, 마지막에万能의 네이버 유저를 찾아서 감사드린다, 그런데 아이디어를 어디서 찾았는지 기억이 나지 않아서, 당황스럽다......
<스크립트 타입="text"/제이스크립트> 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('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" + i + " alt="" /></div></li>'); $("#picture" + i).attr('src', data.result); $("#picPath").append('<input value=' + data.result + type="hidden" id="picurl" + i + /> i++; if (i == resurl.localIds.length - 1) { $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li>'); } up(resurl); } }); } }); } i = 0; } } //이미지 업로드 wx.config(@Html.Raw(ViewBag.config)); wx.ready(function () { $("#picPath").click(function () { wx.chooseImage({ count: 3, // 기본적으로9 sizeType: ['compressed'], // 원본 이미지 또는 압축 이미지를 지정할 수 있습니다. 기본적으로 두 가지 모두 있습니다'original', sourceType: ['album', 'camera'], // 사진의 출처를 앨범이거나 카메라로 지정할 수 있습니다. 기본적으로 두 가지 모두 있습니다 success: function (resu) { var localIds = resu.localIds; // 반환된 선택 사진의 로컬 ID 목록, localId는 img 태그의 src 속성으로 이미지를 표시할 수 있습니다 if (localIds.indexOf("wxlocalresource") != -1) { localIds = localIds.replace("wxlocalresource", "wxLocalResource"); } @(index += 1) if (localIds != '') { $("#picPath").html(""); var sear = new RegExp(','); if (sear.test(localIds)) { up(resu); } else { $("#picPath").append(' <li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" + '@index' + alt="" " /></div></li>'); $("#picture" + "@index").attr('src', localIds); // 사진 업로드 wx.uploadImage({ localId: '' + localIds, isShowProgressTips: 1, success: function (res) { mediaId = res.serverId; $.ajax({ async: false, type: "post", url: "/ActivityRegistration/DownloadWxPhoto", data: { mediaId: mediaId, types: types }, success: function (data) { $("#picPath").append('<input value=' + data.result + type="hidden" id="picurl" + @index + /> $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li>'); } }); } }); } // $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li>'); } } }); }); }); wx.error(function (res) { alert("인터페이스 검증 실패, 자세한 정보:\n" + JSON.stringify(res)); }); </스크립트>
기억해야 할 것은, 재귀는 충분합니다.
이렇게 말하면, 아이는 더 이상 말하지 않고 싶습니다. 이제 이 제품을 더 이상 똑똑하게 하지 마세요, 그리고 그가 웨이백에서 메시지를 받으면 웹 페이지로 이동하는 것을 본 적이 있나요? 그냥 죽어버리세요, 몇 일 전 대阿里의 달력 시간을 생각해보면, 우리 프로그래머는 정말로 슬퍼합니다. 성공한 것은 모두 제품이고, 문제가 발생하면 우리 프로그래머의 책임입니다. 프로그래머가 정말로 그 책임을 지어야 하나요?
그냥 포기해요, 더 이상 할 수 없습니다... 아이92년이 도착했습니다, 지금은 정말로82년의 피부를 생각해보세요, 아이는 피곤합니다, 정말로.
무료로 H를 주세요5페이지의 제안을 해보세요. 예를 들어, 뒤로 가기 버튼을 눌렀을 때, 페이지를 새로 고칠 필요가 있을 때, 이는 페이지를 새로 고칠지 여부를 판단하는 것입니다. 여러 가지 방법이 많지만, 웨이백에서는 아직도 이렇게 하면 신뢰할 만하다고 생각합니다.
<스크립트 타입="text"/제이스크립트> if (window.name != "hasLoad") { location.reload(); window.name = "hasLoad"; } window.name = ""; } </스크립트>
또한, 위챗이 완료되면 즉시 현재 인터페이스에서 위챗 공众 계정 인터페이스로 이동하려면, 위챗의 내장 메서드를 직접 호출할 수 있습니다. <스크립트><에 쓰세요./스크립트>안에 있습니다.
WeixinJSBridge.call('closeWindow'); //이제 위챗에서 현재 웹 페이지를 닫습니다
이렇게 자신감 있게 모든 것을 해결했을 줄 알았지만, 달려보세요, 달려보세요, 아니요, 불만을 가지지 마세요.
위챗 공众 계정이란제10공저는 추가한 것입니다, 하하, 앞의 JS 검증 때 헤더 파일을 제외하고 이러한 일을 어떻게 해결할 수 있었는지, 하하. 아이가 이겼나요? Oh perfect, 저는 이거를 좋아합니다.
<스크립트 src="http://res.wx.qq.com/열림/js/jweixin-1.0.0.js></스크립트>
이거는 잊지 마세요.
이것이 본문의 전체 내용입니다. 많은 도움이 되었기를 바랍니다. 또한, 나아가 튜토리얼을 많이 지지해 주시기 바랍니다.
선언: 본문 내용은 인터넷에서 가져왔으며, 저작권자는 본사입니다. 내용은 인터넷 사용자가 자발적으로 기여하고 업로드한 것이며, 사이트는 소유권을 가지지 않으며, 인공 편집을하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 침해가 의심되는 내용이 있으면, 이메일을 notice#w로 보내 주세요.3codebox.com에 대한 신고는 이메일을 보내고 #을 @으로 변경하세요. 관련 증거를 제공하면, 사이트는 즉시 저작권 침해 내용을 삭제합니다.