春节策划了一个“带现金红包的贺年卡”微信号推广活动,先说下效果:2个小时实现新增关注用户4万多户,活动页面PV达到16.8万,后因红包预算费用原因结束活动。
实现原理:每个人都可以在服务号内发送一张自己的图片,生成定制贺卡,分享后(朋友圈、点对点发给好友、发送到微信群),好友可以打开页面,查看自己送出的祝福,同时还能领现金红包立即到账,并且:自己还能收到回礼红包,钱都由活动方来出,当然啦,领红包的前提是要关注指定微信公众号。
每个人打开活动页面后,利用oauth2获取自己的openid,分享或转发时带上自己的openid,别人打开自己分享的贺卡页面时,获取分享人的openid,用来给其发送回礼红包,同时页面又会获取新打开人员自己的openid,用于领红包。就这样,可以实现无限级裂变传播。
现将通过h5网页获取用户openid的方法步骤简要小结如下:
1、准备认证过的微信服务号、web服务器、通过备案的域名;
2、在公众号设置=》功能设置中设置“网页授权获取用户信息”中,设置自己服务器的域名,也就是公众号JS安全域名;
3、以下为获取openid的核心代码;
第一个页面,用来获取code
testdir.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="testdir.aspx.cs" Inherits="testdir" %>
testdir.aspx.cs
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Linq;
using System.IO;
using ;
using System.Text;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
public partial class testdir : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string openid = Request.QueryString["openid"];
string periods = Request.QueryString["periods"];
Response.Redirect("https://open./connect/oauth2/authorize?appid=你的appid&redirect_uri=http://你的域名/testdirsec.aspx?openid="+openid+"|"+ periods +"&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
}
}
第二个页面,用code来获取openid
testdirsec.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="testdirsec.aspx.cs" Inherits="testdirsec" %>
testdirsec.aspx.cs
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Linq;
using System.IO;
using ;
using System.Text;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using GetOpenId;
public partial class testdirsec : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string all = Request.QueryString["openid"]; //因为oauth2只能传递一个自定义参数,顾自行分割
string[] array=all.Split(new Char[] { '|' });
string fromopenid=array[0];
string periods=array[1];
string code = Request.QueryString["code"];
CGetOpenId goi=new CGetOpenId();
string openid = goi.GetOpenId(code);
Response.Redirect("test.aspx?openid=" + openid + "&periods=" + periods +"&fromopenid=" + fromopenid);
}
}
第三个页面,活动页面,这里只把核心代码展现出来,常规布局没有罗列
test.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="test" %>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<title>我要抢红包</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="/bootstrap/3.3.0/css/bootstrap.min.css">
<link rel="stylesheet" href="/bootstrap/3.3.0/css/bootstrap-theme.min.css">
<style>
body
{
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
}
input[type="button"], input[type="submit"], input[type="reset"]
{
-webkit-appearance: none;
}
textarea
{
-webkit-appearance: none;
}
.divtitle{text-align:center;width:100%;height: 120px;line-height: 120px;font-size: 50px;color:#ffffff;}
.btnsubmit
{
width:85%;
font-size:60px;
height:120px;
border-radius:10px;
background-color:#dddd00;
color: #6f280f;
}
</style>
<script src="/jquery-latest.js"></script>
<script src="http://res./open/js/jweixin-1.2.0.js"></script>
<script>
$.getUrlParam = function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
var test = window.location.href;
var periods=$.getUrlParam('periods') ;
var openid=$.getUrlParam('openid');
$.ajax({
type:"post",
dataType:"json",
contentType:"application/json;charset:utf-8",
data:JSON.stringify({"url":test}),
url:"settest/getset.ashx",
success:function(data)
{
console.log(data);
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '你的公众号appid', // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature,// 必填,签名
jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage'] // 必填,需要使用的JS接口列表
});
wx.ready(function() {
wx.onMenuShareTimeline({
title: "跟我一起抢红包,我已抢到了,好东西必须分享", // 分享标题,朋友圈
link:"http://你的域名与路径/testdir.aspx?openid="+ openid +"&periods="+periods , // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: "http://你的域名与路径/llhb1.jpg" , // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
wx.onMenuShareAppMessage({
title: "跟我一起抢红包", // 分享标题,点对点发送信息给个人或到群里
desc: '我已抢到了,好东西必须分享', // 分享描述
link:"http://你的域名与路径/testdir.aspx?openid="+ openid +"&periods="+periods , // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: "http://你的域名与路径/llhb1.jpg" , // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
})
}
})
</script>
</head>
<body style="text-align:center;width:100%;margin:0 auto;background-color: #ffffff;">
<form id="form1" runat="server">
<asp:Label runat="server" id="lblfromopenid"/></br></br>
<asp:Label runat="server" id="lblopenid"/></br></br>
<asp:Label runat="server" id="lblperiods"/></br></br>
<asp:Label runat="server" id="lblaccesstoken"/></br></br>
<asp:Label runat="server" id="lbuserinfo"/></br></br>
<asp:Label runat="server" id="lbuserinfo1"/>
</form>
</body>
</html>
test.aspx.cs
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.IO;
using System.Text;
using ;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
public partial class test : System.Web.UI.Page
{
string fromopenid,openid,periods;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
fromopenid = Request.QueryString["fromopenid"];
openid = Request.QueryString["openid"];
periods = Request.QueryString["periods"];
lblfromopenid.Text = "fromopenid:" + fromopenid;
lblopenid.Text = "openid:" + openid;
lblperiods.Text = periods;
string strResult="";
string strurl="https://api./sns/userinfo?access_token=" + access_token + "&openid=" + openid + "&lang=zh_CN"; //获取用户信息的 AccessToken
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);
//myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.UTF8);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch
{
strResult = "err";
}
JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));
}
}
}
至此,获取openid已经实现,下面两个文件是用到的类和服务器端处理文件
GetOpenId.cs //内含CGetOpenId类,放在App_Code目录下的,当然如果编译项目的话dll文件就在bin目录下了
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.IO;
using ;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
namespace GetOpenId
{
public class CGetOpenId : System.Web.UI.Page
{
public string GetOpenId(string code)
{
string strResult="";
string openid="";
string strurl="https://api./sns/oauth2/access_token?appid=你的公众号appid&secret=你的公众号secret&code="+ code +"&grant_type=authorization_code";
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);
//myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.UTF8);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch
{
strResult = "err";
}
JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));
openid = obj["openid"].ToString().Replace("\"", "");
return openid;
}
}
}
getset.ashx //在test.aspx中使用,放在服务器settest目录中
<% @ webhandler language="C#" class="getset" %>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.IO;
using ;
using System.Text;
using System.Drawing;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography;
using System.Web.Script.Serialization;
using GetToken;
using GetJSAPI;
public class getset : IHttpHandler
{
public void ProcessRequest(HttpContext ctx)
{
StreamReader sr=new StreamReader(ctx.Request.InputStream);
string stream = sr.ReadToEnd();
JObject jsonObj=JObject.Parse(stream);
string url=jsonObj["url"].ToString().Replace("\"","");
GetAT gt=new GetAT();
string accesstoken=gt.GetToken();
Getjsapi gj=new Getjsapi();
string jsapi=gj.GetAPI();
string timestamp=GetTimeStamp();
string nonceStr="Wm3WZYTfasdPz0wzccnW";
HttpContext.Current.Response.ContentType = "text/plain";
string content="jsapi_ticket="+jsapi+"&noncestr="+nonceStr+"×tamp="+timestamp+"&url="+url;
string sign=SHA1(content, Encoding.UTF8);
Dictionary<String, String> dicList = new Dictionary<String, String>();
dicList.Add("timestamp", timestamp);
dicList.Add("nonceStr", nonceStr);
dicList.Add("signature", sign);
string json =(new JavaScriptSerializer()).Serialize(dicList);
ctx.Response.Write(json);
}
//使用系统自带SHA加密
public string SHA1(string content, Encoding encode)
{
try
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytes_in = encode.GetBytes(content);
byte[] bytes_out = puteHash(bytes_in);
//sha1.Dispose();
string result = BitConverter.ToString(bytes_out);
result = result.Replace("-", "");
return result;
}
catch (Exception ex)
{
throw new Exception("SHA1" + ex.Message);
}
}
//获取时间戳
public string GetTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
public bool IsReusable
{
get { return true; }
}
}
GetToken.cs //在getset.ashx中使用,放在App_Code目录中
//用于获取基础access_token,这个与网页access_token不同,每天使用次数上限为2000,单次有效期7200秒,所以使用数据库保存
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.IO;
using ;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using DbOperate;
namespace GetToken
{
public class GetAT : System.Web.UI.Page
{
public string GetToken()
{
SqlConnection Conn = new SqlConnection(SqlServerDB.ConnStr);
Conn.Open();
SqlCommand Comm = new SqlCommand();
Comm.Connection = Conn;
SqlDataReader dr;
string accesstoken="";
mandText = "select appid,secret,accesstoken,DATEDIFF(second, get_date, getdate()) hour_num from weixin_accesstoken ";
dr=Comm.ExecuteReader();
if(dr.Read())
{
if(Convert.ToInt32(dr["hour_num"].ToString())<=7000)
{
accesstoken=dr["accesstoken"].ToString();
dr.Close();
}
else
{
string strResult;
string strurl="https://api./cgi-bin/token?grant_type=client_credential&appid="+ dr["appid"].ToString() +"&secret="+ dr["secret"].ToString() +"";
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);
//myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.UTF8);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch
{
strResult = "err";
}
//accesstoken=strResult;
//return strResult;
JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));
accesstoken = obj["access_token"].ToString().Replace("\"", "");
dr.Close();
mandText = "update weixin_accesstoken set accesstoken='"+ accesstoken +"',get_date=getdate() ";
Comm.ExecuteScalar();
}
}
if (Conn.State == ConnectionState.Open)
{
Conn.Close();
Conn.Dispose();
}
return accesstoken;
}
}
}
GetJSAPI.cs.cs //在getset.ashx中使用,放在App_Code目录中
//用于获取time_ticket,也是单次有效时限7200秒,用数据库保存
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.IO;
using ;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using GetToken;
using DbOperate;
namespace GetJSAPI
{
public class Getjsapi : System.Web.UI.Page
{
public string GetAPI()
{
SqlConnection Conn = new SqlConnection(SqlServerDB.ConnStr);
Conn.Open();
SqlCommand Comm = new SqlCommand();
Comm.Connection = Conn;
SqlDataReader dr;
string ticket="";
mandText = "select ticket,DATEDIFF(second, get_date, getdate()) time from weixin_jsapi ";
dr=Comm.ExecuteReader();
if(dr.Read())
{
if(Convert.ToInt32(dr["time"].ToString())<=7000)
{
ticket=dr["ticket"].ToString();
dr.Close();
}
else
{
GetAT gt=new GetAT();
string accesstoken=gt.GetToken();
string strResult;
string strurl="https://api./cgi-bin/ticket/getticket?access_token="+accesstoken+"&type=jsapi";
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);
//myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.UTF8);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch
{
strResult = "err";
}
//accesstoken=strResult;
//return strResult;
JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));
ticket = obj["ticket"].ToString().Replace("\"", "");
dr.Close();
mandText = "update weixin_jsapi set ticket='"+ ticket +"',get_date=getdate() ";
Comm.ExecuteScalar();
}
}
if (Conn.State == ConnectionState.Open)
{
Conn.Close();
Conn.Dispose();
}
return ticket;
}
}
}