服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|JavaScript|易语言|

服务器之家 - 编程语言 - PHP教程 - php微信公众账号开发之五个坑(二)

php微信公众账号开发之五个坑(二)

2021-03-01 18:26_Vegetables PHP教程

这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

上篇说到微信公众账号的几个坑,前面五个,已经说到菜单,宝宝继续往下赘述了。可惜,还不知道宝宝的宝宝到底是不是心疼宝宝呢,完了,我凌乱了。。。 

回到正题,我们就不吐槽其他的了,上一篇说到微信的菜单了,那么,我们现在说说菜单回复等等的吧。 

菜单回复是需要处理xml文件的,我们根据微信返回的xml文件,可以得到每个微信用户相对于微信公众号的唯一标识。微信公众平台的机制简单的将就是我们自己输出固定格式的xml文件,然后微信app负责解析,得到我们想要的信息,然后对信息统一处理。 

第六坑,如果你看微信文档,那么,绝对坑死你,上图。这里的tousername和fromusername一定特么的要分清楚了,记住,千万不要写反了,用户对于微信而言是a→b,那么微信对于用户就是反着来的,貌似现在应该说清楚了。

php微信公众账号开发之五个坑(二)

  1. /// <summary> 
  2.  /// 接收微信发送的xml消息并且解析 
  3.  /// </summary> 
  4.  private void receivexml() 
  5.  { 
  6.  try 
  7.  { 
  8.   stream requeststream = system.web.httpcontext.current.request.inputstream; 
  9.   byte[] requestbyte = new byte[requeststream.length]; 
  10.   requeststream.read(requestbyte, 0, (int)requeststream.length); 
  11.   string requeststr = encoding.utf8.getstring(requestbyte); 
  12.  
  13.   if (!string.isnullorempty(requeststr)) 
  14.   { 
  15.  
  16.   //封装请求类 
  17.   xmldocument requestdocxml = new xmldocument(); 
  18.   requestdocxml.loadxml(requeststr); 
  19.   xmlelement rootelement = requestdocxml.documentelement; 
  20.   wxxmlmodel wxxmlmodel = new wxxmlmodel(); 
  21.   if (rootelement != null
  22.   { 
  23.    wxxmlmodel.tousername = rootelement.selectsinglenode("tousername") == null ? "" : rootelement.selectsinglenode("tousername").innertext; 
  24.    wxxmlmodel.fromusername = rootelement.selectsinglenode("fromusername") == null ? "" : rootelement.selectsinglenode("fromusername").innertext; 
  25.    wxxmlmodel.createtime = rootelement.selectsinglenode("createtime") == null ? "" : rootelement.selectsinglenode("createtime").innertext; 
  26.    wxxmlmodel.msgtype = rootelement.selectsinglenode("msgtype") == null ? "" : rootelement.selectsinglenode("msgtype").innertext; 
  27.    switch (wxxmlmodel.msgtype) 
  28.    { 
  29.  
  30.    case "text"://文本 
  31.     wxxmlmodel.content = rootelement.selectsinglenode("content") == null ? "" : rootelement.selectsinglenode("content").innertext; 
  32.     break
  33.    case "image"://图片 
  34.     wxxmlmodel.picurl = rootelement.selectsinglenode("picurl") == null ? "" : rootelement.selectsinglenode("picurl").innertext; 
  35.     break
  36.    case "event"://事件 
  37.     wxxmlmodel.event = rootelement.selectsinglenode("event") == null ? "" : rootelement.selectsinglenode("event").innertext; 
  38.     if (wxxmlmodel.event != "templatesendjobfinish")//关注类型 
  39.     { 
  40.     wxxmlmodel.eventkey = rootelement.selectsinglenode("eventkey") == null ? "" : rootelement.selectsinglenode("eventkey").innertext; 
  41.     } 
  42.     break
  43.    default
  44.     break
  45.    } 
  46.   } 
  47.   responsexml(wxxmlmodel);//回复消息 
  48.   } 
  49.  
  50.   
  51.  
  52.  } 
  53.  catch (exception ee) 
  54.  { 
  55.   //记录错误日志 
  56.  } 
  57.  } 
  58.  
  59.  /// <summary> 
  60.  /// 回复消息 
  61.  /// </summary> 
  62.  /// <param name="wxxmlmodel"></param> 
  63.  private void responsexml(wxxmlmodel wxxmlmodel) 
  64.  { 
  65.  string xml = ""
  66.  switch (wxxmlmodel.msgtype) 
  67.  { 
  68.   case "text"://文本回复 
  69.   var info = oauth.getuserinfo(tools.wa_getaccess_token.isexistaccess_token(), wxxmlmodel.fromusername); 
  70.   tools.waentity.oauthuser user = tools.jsonhelper.parsefromjson<tools.waentity.oauthuser>(info); 
  71.   var content = wxxmlmodel.content.toupper(); 
  72.   string ncbacturl = configurationmanager.appsettings["ncbacturl"]; 
  73.   string appid = configurationmanager.appsettings["appid"]; 
  74.   if (content.contains("t"))//接受的文字如果包含t 
  75.   { 
  76.    //业务处理 
  77.   } 
  78.   else 
  79.   { 
  80.    xml = responsemessage.retext(wxxmlmodel.fromusername, wxxmlmodel.tousername, "/:rose农场大数据欢迎你!/:rose"); 
  81.  
  82.   } 
  83.   break
  84.   case "event"
  85.   switch (wxxmlmodel.event.tolower()) 
  86.   { 
  87.    case "subscribe"
  88.    if (string.isnullorempty(wxxmlmodel.eventkey)) 
  89.    { 
  90.     xml = responsemessage.retext(wxxmlmodel.fromusername, wxxmlmodel.tousername, "关注成功!/:rose"); 
  91.  
  92.    } 
  93.    else 
  94.    { 
  95.     xml = responsemessage.subscanqrcode(wxxmlmodel.fromusername, wxxmlmodel.tousername, wxxmlmodel.eventkey);//扫描带参数二维码先关注后推送事件 
  96.    } 
  97.    break
  98.    case "scan"
  99.    xml = responsemessage.scanqrcode(wxxmlmodel.fromusername, wxxmlmodel.tousername, wxxmlmodel.eventkey);//扫描带参数二维码已关注 直接推送事件 
  100.    break
  101.    case "click"://处理单击事件 
  102.    if (wxxmlmodel.eventkey == "p1"
  103.    { 
  104.     //自己的业务逻辑 
  105.    } 
  106.    else 
  107.    { 
  108.     //自己的业务逻辑 
  109.    } 
  110.    break
  111.    case "unsubscribe"://取消关注 
  112.    break
  113.   } 
  114.   break
  115.   default://默认回复 
  116.   break
  117.  } 
  118.  response.write(xml);//输出组织的xml信息 
  119.  
  120.  } 

这就是菜单的信息处理,不明真相的群众貌似会问那个所谓的responsemessage到底有几个意思呢,ok,我已经无力吐槽我这三天研究出来的微信公共平台的东西了。 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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,加上自己的逻辑代码,是不是完美的实现了回复? 

第七坑,我真心不想计数了,你确定这个回复可以么?说真的,宝宝不确定,因为你写了之后知道在哪里调用么,我的乖乖,尼玛,服务器验证通过就把回复加上去是最保险的。我已经没有节操了。

接下来我们说什么呢,我们就说说获取用户信息这个东西吧,因为我们这些东西一般都是基于h5页面的。所以,就要用到之前我们配置的

php微信公众账号开发之五个坑(二)

这个东东,其实这个相对于前面的至少坑少了很多,真心的,宝宝就暂时不说他坑了。上个代码吧。 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//微信网页授权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")

在这里我还是吐槽一下吧。 

第八坑,微信菜单json的url拼接,里面的前面不是加了js验证么,so,特么的,还是乖乖的加上http://。 

不过这里授权之后,因为用户的很多信息我们都要用到,这就是h5页面传值的问题,我在项目里面用的是session,直接写一个公用方法,如果session有值,则直接取值的。对于里面的一些东东,我想说明一下,并不是所有的代码都要贴出来,我这边的代码只是我个人认为需要贴出来的。所以里面的方法可能有大家看不到的,如果需要,可以留言本宝宝,谢谢。 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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安全验证的问题,这里就是调用这些个验证,请求一些应该的权限,然后获取图片信息等等。 

php微信公众账号开发之五个坑(二)

放心好了,宝宝现在都是上图说话,没图说个小弟弟呀。。。。。 

我们继续回来看代码。 

先来个处理json的

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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(" ", "");
 
 }
 
}

然后看具体调用。

后台代码其实很简单的,直接输出配置文件,然后前台js直接调用即可。 

?
1
2
3
jsapi jsapi = new jsapi();
string config = jsapi.getjsapiinfo(appid, appsecret);
viewbag.config = config;

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<script type="text/javascript">
 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("接口验证失败,详细信息: " + 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");
 
  }
 
 });
 
 }
 
</script>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/// <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有了问题,而且问题不小,上传四张图片吧,老特么是最后一张,最后,找到了万能的网友,感谢你,不过宝宝已经忘记了在哪里找到的了,尴尬了。。。。。。。。。。。 

  1. <script type="text/javascript"
  2.  
  3.  var types = 2; 
  4.  
  5.  var urllist=""
  6.  
  7.  var i = 0; 
  8.  
  9.  function up(resurl) { 
  10.  
  11.   if (i < resurl.localids.length) { 
  12.  
  13.   // 上传照片resu.localids[i] 
  14.   wx.uploadimage({ 
  15.    localid: '' + resurl.localids[i], 
  16.    isshowprogresstips: 1, 
  17.    success: function (res) { 
  18.    // alert("res.serverid:" + res.serverid); 
  19.    mediaid = res.serverid; 
  20.    $.ajax({ 
  21.     async: false
  22.     type: "post"
  23.     url: "/activityregistration/downloadwxphoto"
  24.     data: { mediaid: mediaid, types: types }, 
  25.     success: function (data) { 
  26.     $("#picpath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture' + i + '" alt="" /></div></li>'); 
  27.  
  28.     $("#picture" + i).attr('src', data.result); 
  29.     $("#picpath").append('<input value=' + data.result + ' type="hidden" id="picurl' + i + '" class="picclass" />'); 
  30.  
  31.     i++; 
  32.  
  33.     if (i == resurl.localids.length - 1) { 
  34.  
  35.      $("#picpath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li>'); 
  36.  
  37.     } 
  38.  
  39.     up(resurl); 
  40.     } 
  41.    }); 
  42.  
  43.    } 
  44.   }); 
  45.   } else { 
  46.  
  47.   i = 0; 
  48.   } 
  49.  
  50.  } 
  51.  
  52.   
  53.  
  54.   
  55.  //上传图片 
  56.  wx.config(@html.raw(viewbag.config)); 
  57.  wx.ready(function () { 
  58.   $("#picpath").click(function () { 
  59.   wx.chooseimage({ 
  60.    count: 3, // 默认9 
  61.    sizetype: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有'original', 
  62.    sourcetype: ['album''camera'], // 可以指定来源是相册还是相机,默认二者都有 
  63.    success: function (resu) { 
  64.    var localids = resu.localids; // 返回选定照片的本地id列表,localid可以作为img标签的src属性显示图片 
  65.    if (localids.indexof("wxlocalresource") != -1) {    
  66.    localids = localids.replace("wxlocalresource""wxlocalresource"); 
  67.    } 
  68.   
  69.    @(index += 1) 
  70.    if (localids != '') { 
  71.     $("#picpath").html(""); 
  72.    var sear = new regexp(','); 
  73.     if (sear.test(localids)) { 
  74.     up(resu); 
  75.     } 
  76.  
  77.     else { 
  78.     $("#picpath").append(' <li><div class="imgbox"><img src="/img/cechanadd.png" id="picture' + '@index' + '" alt="" " /></div></li>'); 
  79.     $("#picture" + "@index").attr('src', localids); 
  80.     // 上传照片 
  81.     wx.uploadimage({ 
  82.      localid: '' + localids, 
  83.  
  84.     isshowprogresstips: 1, 
  85.      success: function (res) { 
  86.      mediaid = res.serverid; 
  87.  
  88.      $.ajax({ 
  89.       async: false
  90.  
  91.       type: "post"
  92.       url: "/activityregistration/downloadwxphoto"
  93.  
  94.       data: { mediaid: mediaid, types: types }, 
  95.  
  96.       success: function (data) { 
  97.  
  98.       $("#picpath").append('<input value=' + data.result + ' type="hidden" id="picurl' + @index + '" class="picclass" />'); 
  99.  
  100.       $("#picpath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li>'); 
  101.       } 
  102.      }); 
  103.  
  104.     } 
  105.     }); 
  106.     } 
  107.     // $("#picpath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li>'); 
  108.  
  109.    } 
  110.    } 
  111.   }); 
  112.   }); 
  113.  }); 
  114.  wx.error(function (res) { 
  115.   alert("接口验证失败,详细信息: " + json.stringify(res)); 
  116.  }); 
  117.  </script> 

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

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

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

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

?
1
2
3
4
5
6
7
8
<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。

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

 这个东西一定不能忘记哈。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

延伸 · 阅读

精彩推荐