English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Desarrollo de cuentas de WeChat en PHP: cinco trampas (parte dos)

El artículo anterior habló de algunas trampas del cuenta de WeChat pública, las primeras cinco ya se mencionaron sobre el menú, el bebé sigue detallando. Desafortunadamente, aún no sé si el bebé del bebé realmente se preocupa por el bebé, ¡qué pena, estoy confundido...! 

Volvamos al tema principal, no vamos a hacer chistes sobre otros aspectos, como se mencionó en el artículo anterior sobre el menú de WeChat, por lo tanto, ahora hablemos de las respuestas del menú y otros aspectos. 

La respuesta del menú requiere el procesamiento de archivos 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 ?63"" : rootElement.SelectSingleNode("ToUserName").InnerText;
   WxXmlModel.FromUserName = rootElement.SelectSingleNode("FromUserName") == null ?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"://Texto
    WxXmlModel.Content = rootElement.SelectSingleNode("Content") == null ? "" : rootElement.SelectSingleNode("Content").InnerText;
    break;
   case "image"://Imagen
    WxXmlModel.PicUrl = rootElement.SelectSingleNode("PicUrl") == null ? "" : rootElement.SelectSingleNode("PicUrl").InnerText;
    break;
   case "event"://Evento
    WxXmlModel.Event = rootElement.SelectSingleNode("Event") == null ? "" : rootElement.SelectSingleNode("Event").InnerText;
    if (WxXmlModel.Event != "TEMPLATESENDJOBFINISH")//Tipo de atención
    {
    WxXmlModel.EventKey = rootElement.SelectSingleNode("EventKey") == null ? "" : rootElement.SelectSingleNode("EventKey").InnerText;
    }
    break;
   default:
    break;
   }
  }
  ResponseXML(WxXmlModel);//responder mensaje
  }
 }
 catch (Exception ee)
 {
  //Registrar un registro de errores
 }
 }
 /// <summary>
 /// responder mensaje
 /// </summary>
 /// <param name="WxXmlModel"></param>
 private void ResponseXML(WxXmlModel WxXmlModel)
 {
 string XML = ";
 switch (WxXmlModel.MsgType)
 {
  case "text"://respuesta de texto
  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"))//el texto recibido si contiene T
  {
   //procesamiento de negocios
  }
  else
  {
   XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "/:rose granja de datos grandes bienvenida a ti!/: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);//scanea el código QR con parámetros primero y luego envía el evento
   }
   break;
   case "scan":
   XML = ResponseMessage.ScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//El escaneo del código QR con parámetros ya ha seguido, envía directamente el evento
   break;
   case "click"://Procesar evento de clic
   if (WxXmlModel.EventKey == "p1")
   {
    //mi lógica de negocio
   }
   else
   {
    //mi lógica de negocio
   }
   break;
   case "unsubscribe"://Cancelar la suscripción
   break;
  }
  break;
  default://Respuesta predeterminada
  break;
 }
 Response.Write(XML);//Información XML organizada de salida
 }

Esto es el procesamiento de información del menú, la masa que no sabe la verdad parece preguntar sobre lo que se conoce como ResponseMessage, ¿cuántos significados tiene, OK, ya no tengo fuerza para quejarme de lo que he estudiado durante estos tres días en la plataforma pública de WeChat. 

public class ResponseMessage
{
 #region Tipo de recepción
 /// <summary>
 /// Texto recibido
 /// </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);//Mensaje de texto recibido
 string XML = ";
 switch (Content)
 {
  case "Clave de palabra":
  XML = ReText(FromUserName, ToUserName, "Prueba de respuesta a clave de palabra - Xingnong Fenghua:" + key);
  break;
  case "Single article":
  XML = ReArticle(FromUserName, ToUserName, "Título de prueba", "Detalles de prueba - Xingnong Fenghua:" + key, "http://www.xnfhtech.com/templets/boze/images/20120130083143544.gif", "http://www.xnfhtech.com/");
  break;
  default:
  XML = ReText(FromUserName, ToUserName, "Sin clave de palabra correspondiente - Xingnong Fenghua:" + key);
  break;
 }
 return XML;
 }
 /// <summary>
 /// No ha seguido el escaneo del código QR con parámetros
 /// </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>
 /// ya se ha suscrito al escanear el código QR con parámetros
 /// </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 modo de respuesta
 /// <summary>
 /// Texto de respuesta
 /// </summary>
 /// <param name="FromUserName">a quién se envía (openid)</param>
 /// <param name="ToUserName">de quién viene (ID de cuenta pública)</param>
 /// <param name="Content">texto de respuesta</param>
 /// <returns>XML compuesto</returns>
 public static string ReText(string FromUserName, string ToUserName, string Content)
 {
 string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//A quién se envía (openid), de quién viene (ID de la cuenta pública)
 XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//Timestamp de respuesta
 XML += "<MsgType><![CDATA[text]]></MsgType>";//Tipo de respuesta de texto
 XML += "<Content><![CDATA[" + Content + "]]></Content><FuncFlag>0</FuncFlag></xml>";//el contenido de respuesta FuncFlag se establece a1al mismo tiempo, se marca automáticamente el mensaje recibido recientemente como estrella, adecuado para el uso en estadísticas de eventos
 return XML;
 }
 /// <summary>
 /// Respuesta de un solo artículo
 /// </summary>
 /// <param name="FromUserName">a quién se envía (openid)</param>
 /// <param name="ToUserName">de quién viene (ID de cuenta pública)</param>
 /// <param name="Title">título</param>
 /// <param name="Description">detalles</param>
 /// <param name="PicUrl">dirección de imagen</param>
 /// <param name="Url">dirección</param>
 /// <returns>XML compuesto</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>";//A quién se envía (openid), de quién viene (ID de la cuenta pública)
 XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//Timestamp de respuesta
 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>
 /// Respuesta de múltiples artículos
 /// </summary>
 /// <param name="FromUserName">a quién se envía (openid)</param>
 /// <param name="ToUserName">de quién viene (ID de cuenta pública)</param>
 /// <param name="ArticleCount">数量 de artículos</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>";//A quién se envía (openid), de quién viene (ID de la cuenta pública)
 XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//Timestamp de respuesta
 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, añade tu código lógico, ¿no se ha implementado perfectamente la respuesta? 

El séptimo hoyo,Realmente no quiero contar más, ¿estás seguro de que esta respuesta es correcta? En serio, el bebé no está seguro, porque después de que lo escribiste, ¿sabes dónde llamarlo? Mi cariño, ¡ni ma ma, si el servidor verifica correctamente, es más seguro agregar la respuesta. Ya no tengo decencia.

Lo que vamos a decir a continuación, vamos a hablar de obtener esta cosa de información del usuario, porque todas estas cosas generalmente se basan en H5de la página. Por lo tanto, es necesario usar la configuración anterior que hemos configurado

Este objeto, de hecho, es mucho menos problemático que el anterior, sinceramente, bebé, por ahora no lo mencionaré como problemático. Vamos a ver el código. 

//Autorización de página web de WeChat2.0
public class Oauth2
{
 JavaScriptSerializer Jss = new JavaScriptSerializer();
 public Oauth2() { }
 /// <summary>
 /// Si la página necesita usar la autorización
 /// </summary>
 /// <param name="Appid">ID de aplicación de WeChat</param>
 /// <param name="redirect_uri">Página de retroalimentación</param>
 /// <param name="scope">Ámbito de autorización de aplicación snsapi_userinfo (sin abrir la página de autorización, saltar directamente, solo se puede obtener el openid del usuario), snsapi_userinfo (abrir la página de autorización, se puede obtener el nombre de usuario, género y ubicación a través del openid. Además, incluso si el usuario no ha seguido, siempre que el usuario autorice, también se puede obtener su información)</param>
 /// <returns>Dirección de autorización</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>
 /// Si la página necesita usar la autorización
 /// </summary>
 /// <param name="Appid">ID de aplicación de WeChat</param>
 /// <param name="redirect_uri">Página de retroalimentación</param>
 /// <param name="scope">Ámbito de autorización de aplicación snsapi_userinfo (sin abrir la página de autorización, saltar directamente, solo se puede obtener el openid del usuario), snsapi_userinfo (abrir la página de autorización, se puede obtener el nombre de usuario, género y ubicación a través del openid. Además, incluso si el usuario no ha seguido, siempre que el usuario autorice, también se puede obtener su información)</param>
 /// <returns>Dirección de autorización</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>
 /// Canjear openid con code, este método generalmente se utiliza cuando no se necesita obtener el nombre de usuario del usuario
 /// </summary>
 /// <param name="Appid"></param>
 /// <param name="Appsecret"></param>
 /// <param name="Code">Parámetro de código de la página de retorno</param>
 /// <returns>Identificador único de usuario de WeChat 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, "");//método post/método get para obtener información
 Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText);
 if (!DicText.ContainsKey("openid"))
  return "";
 return DicText["openid"].ToString();
 }
 /// <summary>
 ///Obtener información del usuario utilizando el código (incluso para usuarios no suscritos)
 /// </summary>
 /// <param name="Appid"></param>
 /// <param name="Appsecret"></param>
 /// <param name="Code">Parámetro de código de la página de retorno</param>
 /// <returns>Obtener información del usuario (formato 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, "");//método post/método get para obtener información
 Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText);
 if (!DicText.ContainsKey("openid"))
 {
  log.Error("Fallo al obtener openid, código de error:", + 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>
 /// Obtener información del usuario a través de 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, "");//método post/método get para obtener información
 }
}

Cuando necesitemos llamar, podemos usar directamente los métodos dentro, obtener la autorización de la página web de WeChat, por ejemplo, para obtener la autorización y la información relevante del usuario bajo el controlador A y la vista B, podemos llamar directamente, como GetCodeUrl(appid, "http://" + Url + "/A/"B", "snsapi_userinfo")

Aquí sigo quejándome. 

El octavo problema,La combinación de URL de JSON del menú de WeChat, que ya no se añadió la verificación de js en el principio, así que, pacientemente, añade http://. 

Sin embargo, aquí después de la autorización, ya que necesitamos mucha información del usuario, esto es H5Se trata de un problema de valor de página, en mi proyecto uso Session, y escribo un método común. Si Session tiene un valor, toma directamente el valor. Respecto a algunas cosas dentro, quiero explicar que no todos los códigos deben estar aquí, este código es solo lo que considero necesario. Por lo tanto, algunos métodos pueden no ser visibles para todos, si es necesario, puede dejar un mensaje, gracias. 

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

然后每次遇到需要获取信息的页面,我一般都是调用这个就可以了。 

基本上剩下的都是我们自己要处理的业务逻辑了,继续说坑吧。 

第九坑,微信上传图片,坑的绝对不只是自己。对于这个宝宝真的信了,不管你信不信。特么的图片不能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/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 = "";
 //caché de ticket7200 segundos
 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();//Obtener ticket
 string timestamp = CommonMethod.ConvertDateTimeInt(DateTime.Now).ToString();//Generar el timestamp de la firma}
 string nonceStr = CommonMethod.GetRandCode(16);//Generar una secuencia de números aleatorios para la firma
 string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.ToString();//La dirección actual
 BasicApi.WriteTxt("url:", + url);
 string[] ArrayList = { "jsapi_ticket=" + jsapi_ticket, "timestamp=", + timestamp, "noncestr=", + nonceStr, "url=", + url };
 Array.Sort(ArrayList);
 string signature = string.Join("&", ArrayList);
 string 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(" ", "");
 }
}

Luego veamos la llamada específica.

El código en el servidor es muy simple, directamente salida del archivo de configuración, luego el js en la interfaz de usuario llama directamente. 

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

Código en la interfaz de usuario, realmente no es difícil, hay ejemplos oficiales. 

<script type="text"/javascript">
 wx.config(@Html.Raw(ViewBag.config));//Archivo de configuración transmitido por el backend
 wx.ready(function () {
 $("#avatar").click(function () {
  wx.chooseImage({
  count: 1, // Número de imágenes por defecto9
  sizeType: ['compressed'], // se puede especificar si es la imagen original o la imagen comprimida, por defecto ambos están disponibles'original',
  sourceType: ['album', 'camera'], // se puede especificar si la fuente es la galería o la cámara, por defecto ambos están disponibles
  success: function (res) {
   var localIds = res.localIds; // devolver la lista de ID locales de las fotos seleccionadas, localId puede ser utilizado como atributo src de img tag para mostrar la imagen
   wx.uploadImage({
   localId: '' + localIds,
   isShowProgressTips: 1,
   success: function (res) {
    serverId = res.serverId;
    getWxPhoto(serverId);
   }
   });
  }
  });
 });
 });
 wx.error(function (res) {
 alert("La verificación de la interfaz ha fallado, detalles: \n" + JSON.stringify(res));
 });
 var types = 1;
 function getWxPhoto(mediaId) {
 $.ajax({
  async: false,
  type: "post",
  url: "/ActivityRegistration/DownloadWxPhoto"//Propia forma de procesar
  data: { mediaId: mediaId, types: types },
  success: function (data) {
  $("#imageico").val(data.result);
  $("#hed_pic").attr('src', ".."); + data.result);
  $("#hed_pic").attr('alt', "avatarImg");
  }
 });
 }
</script>

Bien, el método en el backend es realmente simple, es un procesamiento de archivos binarios, no, ¿qué es simple? El maldito, porque el problema de la ruta, perdi una hora de mi vida, maldito. Además, aquí te recomiendo, espera a que la descarga de la imagen de WeChat se complete antes de cargar la imagen en la interfaz de usuario, asegúrate de que cada imagen se cargue completamente, asegúrate de que la carga de la imagen en el backend se complete. 

/// <summary>
/// Descarga de archivos multimedia
/// </summary>
/// <param name="userName">Nombre de la cuenta de公众号</param>
/// <param name="mediaId">ID de medios</param>
/// <param name="data">Devuelve si la descarga fue exitosa</param>
/// <param name="types">Añade el tipo de imagen</param>
/// <returns>Devuelve los datos del archivo multimedia; si la descarga falla, devuelve 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, "Download of multimedia file successful.");
 }
 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 beginning of the file
 pReadByte = r.ReadBytes((int)r.BaseStream.Length);
 return pReadByte;
 }
 catch
 {
 return pReadByte;
 }
 finally
 {
 if (pFileStream != null)
  pFileStream.Close();
 }
}
//write byte[] to 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>
/// Determina si el array de bytes objetivo se encuentra al principio del array de bytes de origen
/// </summary>
/// <param name="source">Array de bytes de origen</param>
/// <param name="target">Array de bytes objetivo</param>
/// <returns>Devuelve si el array de bytes objetivo se encuentra al principio del array de bytes de origen</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;
}

 ¿Crees que esto es todo, mi querido, se subió la foto de perfil, también se debería llamar a la cámara de WeChat, el bebé está muy feliz, el bebé también es un genio, recuerda lo que dije antes, el bebé aún no ha dicho el agujero.
Vamos a repetir nuestro noveno agujero, maldito, si tu JS escribiera un bucle for que pudiera subir imágenes al backend, el bebé también estaría impresionado, en serio, el bebé está impresionado. 

Dímelo directamente, después de pensarlo por mí mismo y discutirlo con los compañeros de equipo, puede que sea por alguna verificación de WeChat, que después de que una imagen se subió con éxito, se puede proceder con la siguiente, pero nuestro iPhone es un caso especial, el gran Android no tiene problemas, pero el iPhone tiene problemas, y no son pocos, sube cuatro imágenes, siempre es la última, finalmente, encontré al sabio de Internet, gracias, pero el bebé ya ha olvidado dónde lo encontró, es bochornoso...... 

<script type="text"/javascript">
 var types = 2;
 var urlList="";
 var i = 0;
 function up(resurl) {
  if (i < resurl.localIds.length) {
  // subir foto 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 + " class="picclass" /">
    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;
  }
 }
 //subir imagen
 wx.config(@Html.Raw(ViewBag.config));
 wx.ready(function () {
  $("#picPath").click(function () {
  wx.chooseImage({
   count: 3, // por defecto9
   sizeType: ['compressed'], // se puede especificar si es la imagen original o la imagen comprimida, por defecto ambos están disponibles'original',
   sourceType: ['album', 'camera'], // se puede especificar si la fuente es la galería o la cámara, por defecto ambos están disponibles
   success: function (resu) {
   var localIds = resu.localIds; // devolver la lista de ID locales de las fotos seleccionadas, localId puede ser utilizado como atributo src de img tag para mostrar la imagen
   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);
    // Subir fotografía
    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 + " class="picclass" /">
      $("#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("La verificación de la interfaz ha fallado, detalles: \n" + JSON.stringify(res));
 });
 </script>

Recuerda, la recursión es más que suficiente.

Hasta aquí, el bebé ya no quiere decir más, ¿puedes dejar de actuar como un hipócrita, ¿has visto algún WeChat que pueda responder un mensaje y saltar directamente a una página web? ¿Por qué no te vas a la mierda? Al recordar el tiempo de la luna de miel de la gran Ali de hace unos días, de repente siento que los programadores somos bastante trágicos, los éxitos son todos el maldito producto, y luego los problemas son la culpa de los programadores. ¿Alguna vez te has preguntado si realmente es la culpa de los programadores? 

Bueno, no me quejaré más, ya no tengo fuerza ni energía ... bebé92Llegó, ahora es realmente82La piel del año, oh, el bebé está cansado, de verdad. 

Dale un poco de H5Sugerencias de la página. Por ejemplo, cuando se presiona el botón de retroceso, cuando necesitamos refrescar la página, es lo que se conoce como determinar si la página debe refrescarse, aquí hay muchas maneras, pero en WeChat, el bebé aún considera que así es más confiable. 

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

Además, si quieres salir directamente de la interfaz actual a la interfaz de la cuenta de WeChat pública después de que WeChat se ejecute, puedes llamar directamente a un método integrado de WeChat. Recuerda escribirlo en <script></dentro de script> 

WeixinJSBridge.call('closeWindow'); //Esto es cerrar la página actual de WeChat

Tan seguro de que ha resuelto todo, corre, corre, no te rindas. 

Cuenta de WeChat públicaOctavo agujeroEsto es lo que yo añadí, ¡jaja! Es el JS de verificación anterior, no necesitas el archivo de encabezado, ¿cómo manejas estas cosas, jaja. ¿No ganó el bebé? ¡Oh, perfecto, me gusta!

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

 Este punto no debe olvidarse.

Esto es todo el contenido de este artículo, espero que ayude en su aprendizaje y que todos lo apoyen a la enseñanza de gritos.

Declaración: El contenido de este artículo se ha obtenido de la red, pertenece al autor original, el contenido se ha contribuido y subido por los usuarios de Internet de manera autónoma. Este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume responsabilidad alguna por las responsabilidades legales. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplaza # con @) para denunciar, y proporciona evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustará