Maison  >  Article  >  Applet WeChat  >  Résumé de cinq pièges rencontrés dans le développement de comptes publics PHP WeChat

Résumé de cinq pièges rencontrés dans le développement de comptes publics PHP WeChat

高洛峰
高洛峰original
2017-03-21 15:54:353044parcourir

Cet article présente principalement en détail les cinq pièges du développement de comptes publics PHP WeChat. Il a une certaine valeur de référence. Les amis intéressés peuvent se référer au menu

La réponse doit être traitée. Fichier XML Sur la base du fichier XML renvoyé par WeChat, nous pouvons obtenir l' identifiant unique de chaque utilisateur WeChat par rapport au compte officiel WeChat . Le mécanisme de la plate-forme publique WeChat consiste simplement à générer nous-mêmes un fichier XML au format fixe, puis l'application WeChat est chargée de l'analyser, d'obtenir les informations souhaitées, puis de traiter les informations de manière unifiée.

Le sixième gouffre, Si vous regardez le document WeChat, alors il vous tuera certainement, comme le montre l'image ci-dessus. Le ToUserName et FromUserName ici doivent être clairement distingués. N'oubliez pas de ne jamais les écrire à l'envers. L'utilisateur est A → B pour WeChat, donc WeChat est l'inverse pour l'utilisateur.

Résumé de cinq pièges rencontrés dans le développement de comptes publics PHP WeChat


/// <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;
   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"://文本
    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);//扫描带参数二维码先关注后推送事件
   }
   break;
   case "scan":
   XML = ResponseMessage.ScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//扫描带参数二维码已关注 直接推送事件
   break;
   case "click"://处理单击事件
   if (WxXmlModel.EventKey == "p1")
   {
    //自己的业务逻辑
   }
   else
   {
    //自己的业务逻辑
   }
   break;
   case "unsubscribe"://取消关注
   break;
  }
  break;
  default://默认回复
  break;
 }
 Response.Write(XML);//输出组织的XML信息

 }

C'est le traitement de l'information du menu. Les gens qui ne connaissent pas la vérité semblent se demander ce qu'il en est. -appelé ResponseMessage signifie OK, je ne peux plus me plaindre de la plateforme publique WeChat que j'ai recherchée au cours des trois derniers jours.


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>
 /// 未关注扫描带参数二维码
 /// </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>
 /// 已关注扫描带参数二维码
 /// </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

 }

OK, avec votre propre code logique, la réponse est-elle parfaitement implémentée ?

La septième fosse, Je n'ai vraiment plus envie de compter, es-tu sûr que cette réponse est bonne ? Pour être honnête, je ne suis pas sûr, car après l'avoir écrit, savez-vous où l'appeler ? Mon cher, bon sang, il est plus sûr d'ajouter la réponse une fois que le serveur a réussi la vérification. Je n'ai plus de morale.

Que devrions-nous dire ensuite ? Parlons de l'obtention d'informations sur les utilisateurs, car nos choses sont généralement basées sur des pages H5. Il faut donc utiliser le

Résumé de cinq pièges rencontrés dans le développement de comptes publics PHP WeChat

que nous avons configuré auparavant. En fait, par rapport au précédent, celui-ci a au moins beaucoup moins d'embûches. , bébé, ce sera temporaire. Sans oublier qu'il a été trompé. Mettons du code.


//微信网页授权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方法获取信息

 }

}

Lorsque nous avons besoin de l'appeler, nous pouvons directement utiliser la méthode à l'intérieur pour obtenir l'autorisation de la page Web WeChat. Par exemple, nous devons obtenir l'autorisation pour la vue B. sous Un contrôleur, et pour obtenir des informations relatives à l'utilisateur, nous pouvons l'appeler directement, comme GetCodeUrl(appid, "http://" Url "/A/B", "snsapi_userinfo")

Ici, je continue à nous plaindre.

Le huitième puits, Épissage d'url JSON du menu WeChat, n'y a-t-il pas de vérification js à l'avant, alors, bon sang, ajoutez simplement http://.

Mais après autorisation ici, parce que nous avons besoin d'utiliser beaucoup d'informations sur l'utilisateur, c'est le problème du transfert de valeur sur la page H5. J'utilise Session dans le projet et j'écris directement une méthode publique. . Si Si Session a une valeur, elle est prise directement. Concernant certains éléments contenus à l'intérieur, je voudrais expliquer que tout le code n'a pas besoin d'être publié. Le code ici est exactement ce que je pense personnellement qui doit être publié. Il se peut donc que vous ne puissiez pas voir certaines méthodes. Si nécessaire, vous pouvez laisser un message sur cette page. Merci.


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; };

}

Ensuite, chaque fois que je rencontre une page qui a besoin d'obtenir des informations, j'appelle généralement ainsi.

En gros, le reste est la logique métier que nous devons gérer nous-mêmes, continuons à parler des pièges.

Le neuvième écueil, télécharger des photos sur WeChat n'est certainement pas le seul écueil pour vous. Je crois vraiment en ce bébé, que tu le croies ou non. Les images spéciales ne peuvent pas être téléchargées dans une boucle for. Bien entendu, cela ne concerne que les modèles Apple, il n'y a toujours aucun problème avec Android.
J'ai mentionné plus tôt le problème de la vérification de la sécurité JS. Ici, nous appelons ces vérifications, demandons certaines autorisations appropriées, puis obtenons des informations sur l'image, etc.

Résumé de cinq pièges rencontrés dans le développement de comptes publics PHP WeChat

Ne vous inquiétez pas, le bébé parle de la photo ci-dessus, pas d'un petit frère. . . . .

Continuons à revenir et à regarder le code.

Traitons d'abord de 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 验证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 = "";

 //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/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<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(jsapi_ticket);
 jsapi_ticket = respDic["ticket"].ToString();//获取ticket
 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(" ", "");

 }

}

, puis examinons les appels spécifiques.

Le code d'arrière-plan est en fait très simple, il suffit de sortir directement le fichier de configuration, puis d'appeler directement le js front-end.


JsApi jsApi = new JsApi();
string config = jsApi.GetJsApiInfo(appId, appSecret);
ViewBag.config = config;

前台代码,其实也不难,这个有官方的例子的。 


<script type="text/javascript">
 wx.config(@Html.Raw(ViewBag.config));//后台传递的微信配置文件
 wx.ready(function () {
 $("#avatar").click(function () {
  wx.chooseImage({
  count: 1, // 图片数量 默认9
  sizeType: [&#39;compressed&#39;], // 可以指定是原图还是压缩图,默认二者都有&#39;original&#39;,
  sourceType: [&#39;album&#39;, &#39;camera&#39;], // 可以指定来源是相册还是相机,默认二者都有
  success: function (res) {
   var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
   wx.uploadImage({
   localId: &#39;&#39; + 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(&#39;src&#39;, ".." + data.result);
  $("#hed_pic").attr(&#39;alt&#39;, "avatarImg");

  }

 });

 }

</script>

OK,后台方法其实也很简单,就是一个二进制文件处理,不对,简单个蛋蛋,特么的,因为路径的问题,坑了宝宝一个小时,特么的。还有这里建议,等微信图片下载完成之后再给前台加载图片,保证每一个图片都加载完成,保证后台的图片的上传完成。 


/// <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;

}

 是不是以为这就算完事了,我的乖乖,头像上传了,微信摄像头也特么该调用的调用了,宝宝好幸福,宝宝也是牛人一个了,记住前面的东东,宝宝还没有说坑呢。
来重复我们的第九个坑,特么的,你JS写个for循环要是能循环把图片上传到后台,宝宝也服气,真的,宝宝服气。 

直接说吧,最后我自己想了下,也和队友讨论了下,可能是因为微信有什么验证,导致之后一张图片上传成功之后,才能进行一张,但是我们Iphone就是特么的特例,大Android没用问题的,就是Iphone有了问题,而且问题不小,上传四张图片吧,老特么是最后一张,最后,找到了万能的网友,感谢你,不过宝宝已经忘记了在哪里找到的了,尴尬了。。。。。。。。。。。 


<script type="text/javascript">

 var types = 2;

 var urlList="";

 var i = 0;

 function up(resurl) {

  if (i < resurl.localIds.length) {

  // 上传照片resu.localIds[i]
  wx.uploadImage({
   localId: &#39;&#39; + 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(&#39;<li><p class="imgbox"><img src="/img/cechanadd.png" id="picture&#39; + i + &#39;" alt="" /></p></li>&#39;);

    $("#picture" + i).attr(&#39;src&#39;, data.result);
    $("#picPath").append(&#39;<input value=&#39; + data.result + &#39; type="hidden" id="picurl&#39; + i + &#39;" class="picclass" />&#39;);

    i++;

    if (i == resurl.localIds.length - 1) {

     $("#picPath").append(&#39;<li><p class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></p></li>&#39;);

    }

    up(resurl);
    }
   });

   }
  });
  } else {

  i = 0;
  }

 }

 

 
 //上传图片
 wx.config(@Html.Raw(ViewBag.config));
 wx.ready(function () {
  $("#picPath").click(function () {
  wx.chooseImage({
   count: 3, // 默认9
   sizeType: [&#39;compressed&#39;], // 可以指定是原图还是压缩图,默认二者都有&#39;original&#39;,
   sourceType: [&#39;album&#39;, &#39;camera&#39;], // 可以指定来源是相册还是相机,默认二者都有
   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 != &#39;&#39;) {
    $("#picPath").html("");
   var sear = new RegExp(&#39;,&#39;);
    if (sear.test(localIds)) {
    up(resu);
    }

    else {
    $("#picPath").append(&#39; <li><p class="imgbox"><img src="/img/cechanadd.png" id="picture&#39; + &#39;@index&#39; + &#39;" alt="" " /></p></li>&#39;);
    $("#picture" + "@index").attr(&#39;src&#39;, localIds);
    // 上传照片
    wx.uploadImage({
     localId: &#39;&#39; + 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(&#39;<input value=&#39; + data.result + &#39; type="hidden" id="picurl&#39; + @index + &#39;" class="picclass" />&#39;);

      $("#picPath").append(&#39;<li><p class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></p></li>&#39;);
      }
     });

    }
    });
    }
    // $("#picPath").append(&#39;<li><p class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></p></li>&#39;);

   }
   }
  });
  });
 });
 wx.error(function (res) {
  alert("接口验证失败,详细信息:\n" + JSON.stringify(res));
 });
 </script>

请记住,递归就特么可以了。

说到这里,宝宝已经不想多说什么了,特么的产品你能不能不装逼,你特么见过那个微信能回复一个信息直接跳转网页的,你咋不去屎呢,联想到前几天大阿里的月饼时间,突然感觉我们程序员挺悲剧的,成功的都是特么的产品,然后出问题的都是我们程序员的锅?试问一下,这个锅真心我们程序员该背么。 

算了,还是不吐槽了,已经无力了。。。。宝宝92年降临,现在确实82年的皮肤呀,唉,宝宝累了,真的。 

顺便给点H5页面的建议吧。比如当点击返回键的时候,我们需要刷新页面的时候,就是所谓的判断页面要不要刷新,这里有很多种方法,但是微信里面宝宝还是觉得这么干靠谱。 


<script type="text/javascript">
 if (window.name != "hasLoad") {
 location.reload();
 window.name = "hasLoad";
 } else {
 window.name = "";
 }
</script>

还有,那个微信执行完成之后想直接退出当前界面进入微信公众号界面的,直接调用微信的一个内置的方法即可。记得写到<script></script>里面。 

WeixinJSBridge.call('closeWindow'); //这是微信关闭当前网页

这么自信的以为自己搞定了所有,你跑呀,你要跑起来,嗯哼,别不服气。 

微信公众账号指第十坑,我自己加的,哈哈,就是前面的JS验证的时候,你不要头文件,怎么搞定这些事情,哈哈。是不是宝宝赢了。Oh  perfect,I like it。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn