最近有群里的小伙子咨询怎么实现微信里打开网页分享到朋友或者朋友圈
实现只需要三步
第一步 阅读文档
阅读微信开发者文档,作为一名开发,能够理解文档所说的尤其重要,可以说这是一个程序员和另外一个程序的间接沟通。话不多说上截图
首先打开微信官方文档,找到JSSDK使用步骤
这一部尤其重要 在进行微信网页开发基本上都需要进行wx.config初始化
从上面看到的参数最重要的是获取到signature(签名)
如何获取签名呢
找到此个位置 看到这里 意思就是我们
先得获取access_token
在通过access_token获取jsapi_ticket
最后通过签名算法得到signtrue
那不就简单了
第二步 上代码解析
先上几个基础的实体模型
access_token实体类
public class AccessToken
{
public string access_token { get; set; }
public int expires_in { get; set; }
}
获取Ticket实体类
public class JsApiTicketResult
{
public int errcode { get; set; }
public string errmsg { get; set; }
public string ticket { get; set; }
public int expires_in { get; set; }
}
最终需要获取的实体模型
public class WxConfigModel
{
public bool debug { get; set; }
public string appId { get; set; }
public string timestamp { get; set; }
public string nonceStr { get; set; }
public string jsapi_ticket { get; set; }
public string signature { get; set; }
}
H5的基本配置类
public class H5WxConfig
{
private H5WxConfig()
{
}
//获取用户信息的Access_token
public string GET_USER_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type={3}";
//获取用户信息的Access_token
public string REFRESH_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={0}&grant_type=refresh_token&refresh_token={1}";
/// <summary>
/// 获取用户信息
/// </summary>
public string GAIN_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN";
/// <summary>
/// 获取保存到服务器的Access
/// </summary>
public string GAIN_H5_ACCESS="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
/// <summary>
/// 获取保存到服务区的Ticket
/// </summary>
public string GAIN_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi";
/// <summary>
/// 公众号的唯一标识
/// </summary>
public string APPID = "自己公众号的appid";
/// <summary>
/// 公众号的appsecret
/// </summary>
public string SERCERT = "填写你自己的密钥";
/// <summary>
/// 填写为authorization_code
/// </summary>
public string GRANT_TYPE = "authorization_code";
private static class InnerH5WxConfig
{
public static readonly H5WxConfig SingleTon = new H5WxConfig();
}
public static H5WxConfig GetH5WxConfigSingleTon()
{
return InnerH5WxConfig.SingleTon;
}
}
获取H5一些资源的辅助类
public class AuthHelper
{
/// <summary>
/// 获取AccessToken
/// </summary>
public static AccessToken GetAccessToken()
{
string url = string.Format(GetConfig.GAIN_H5_ACCESS, GetConfig.APPID, GetConfig.SERCERT);
return HttpHelper.Get<AccessToken>(url);
}
/// <summary>
/// 获取ticket
/// </summary>
/// <param name="code"></param>
public JsApiTicketResult GetTicket(string acctessToken)
{
string url = string.Format(GetConfig.GAIN_TICKET_URL, acctessToken);
JsApiTicketResult jsApiTicketResult = HttpHelper.Get<JsApiTicketResult>(url);
return jsApiTicketResult;
/// <summary>
/// 获取配置属性
/// </summary>
public static H5WxConfig GetConfig
{
get
{
return H5WxConfig.GetH5WxConfigSingleTon();
}
}
}
网络请求的辅助类
public class HttpHelper
{
public static T Get<T>(string Url)
{
try
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Get(Url));
}
catch (Exception ex)
{
return default(T);
}
}
public static T Post<T>(string Url, string Data, string Referer = "")
{
try
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Post(Url, Data, Referer));
}
catch (Exception ex)
{
return default(T);
}
}
public static string Get(string Url)
{
//System.GC.Collect();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Proxy = null;
request.KeepAlive = false;
request.Method = "GET";
request.ContentType = "application/json; charset=UTF-8";
request.AutomaticDecompression = DecompressionMethods.GZip;
request.Timeout = 180000; //3分钟
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream myResponseStream = response.GetResponseStream();
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);
string retString = myStreamReader.ReadToEnd();
myStreamReader.Close();
myResponseStream.Close();
if (response != null)
{
response.Close();
}
if (request != null)
{
request.Abort();
}
return retString;
}
public static string Post(string Url, string Data, string Referer = "")
{
return certPost(Url, Data, Referer, null);
}
public static T certPost<T>(string Url, string Data, string Referer = "", X509Certificate2 cert = null)
{
try
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(certPost(Url, Data, Referer, cert));
}
catch (Exception ex)
{
string info = ex.Message + "\r\n";
info += ex.StackTrace + "\r\n";
Logger.WriteLog(info);
return default(T);
}
}
public static string certPost(string Url, string Data, string Referer = "", X509Certificate2 cert = null)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Method = "POST";
if (cert != null)
request.ClientCertificates.Add(cert);
//request.Referer = string.IsNullOrWhiteSpace(Referer) ? Url + Data : Referer;
byte[] bytes = Encoding.UTF8.GetBytes(Data);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = bytes.Length;
Stream myResponseStream = request.GetRequestStream();
myResponseStream.Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader myStreamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string retString = myStreamReader.ReadToEnd();
myStreamReader.Close();
myResponseStream.Close();
if (response != null)
{
response.Close();
}
if (request != null)
{
request.Abort();
}
return retString;
}
}
核心代码
上面的把前提的基础都做好了 才好进行小试牛刀
从上面的文档提示过我们 我们不能频繁的去调用access_token 微信那边是有限制调用频率的 而且微信那边是要求我们保存到服务器端 那不就简单了 上代码 下面这个类是属于基本的业务类 上面的是我封装到另外一个类库的
public class H5Helper
{
/// <summary>
/// 得到微信通用后端token
/// 有效期是7200秒 5分钟的过渡时间
/// 设置7000秒 Redis3分钟过渡时间
/// </summary>
/// <returns></returns>
public static readonly object GetH5AccessToken_LOCK = new object();
public static string GetH5AccessToken()
{
lock (GetH5AccessToken_LOCK)
{
Cache cache = new Cache();
AccessToken accessTokenResult = cache.Get("H5_ACCESS_TOKEN") as AccessToken;
if (accessTokenResult == null)
{
accessTokenResult = AuthHelper.GetAccessToken();
cache.Insert("H5_ACCESS_TOKEN", accessTokenResult, null, DateTime.Now.AddMinutes(115), Cache.NoSlidingExpiration);
}
return accessTokenResult.access_token;
}
}
/// <summary>
/// 得到Ticket
/// </summary>
/// <returns></returns>
public static readonly object GetTicket_LOCK = new object();
public static string GetTicket()
{
lock (GetTicket_LOCK)
{
Cache cache = new Cache();
WeChatPublic.H5.Model.JsApiTicketResult jsApiTicketResult = cache.Get("TICKET") as WeChatPublic.H5.Model.JsApiTicketResult;
if (jsApiTicketResult == null)
{
jsApiTicketResult = new AuthHelper().GetTicket(H5Helper.GetH5AccessToken());
cache.Insert("TICKET", jsApiTicketResult, null, DateTime.Now.AddMinutes(115), Cache.NoSlidingExpiration);
}
return jsApiTicketResult.ticket;
}
}
}
解读下 用lock的目的是防止并行 同一时间点多次执行 上面是用了.NetFramwork框架里面的缓存,也能115分钟平滑的过度 注意 微信那边是115分钟刷新一次 115-120分钟区间 老的access_token还是可以用的 目的就是用来平滑过渡的
到这里基本上完成一大部分了
核心实现类
/// <summary>
/// SDK权限验证
/// </summary>
/// <param name="ticket">上面生成的ticket</param>
/// <param name="url">完成的请求路径 </param>
/// <returns></returns>
public WxConfigModel CreateWxConfig(string ticket,string url)
{
var timestamp = this.ConvertDateTimeInt(DateTime.Now);//获取时间戳
var nonceStr = this.GetRandomString(10);//获取随机字符串
var orgStr = string.Format("jsapi_ticket={0}&noncestr={1}×tamp={2}&url={3}", ticket, nonceStr, timestamp, url);
var signature = this.Sha1(orgStr);
var tag = new WxConfigModel()
{
appId = GetConfig.APPID, // 必填,公众号的唯一标识
timestamp = timestamp.ToString(), // 必填,生成签名的时间戳
nonceStr = nonceStr, // 必填,生成签名的随机串
jsapi_ticket = ticket, //选填 调用微信JS的临时票据
signature = signature,// 必填,签名,见附录1
};
return tag;
}
public static long ConvertDateTimeInt(DateTime time)
{
var startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0));
var t = (time.Ticks - startTime.Ticks) / 10000000; //除10000000调整为10位
return t;
}
/// <summary>
/// 生成随机串
/// </summary>
/// <param name="length">字符串长度</param>
/// <returns></returns>
public static string GetRandomString(int length)
{
const string key = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
if (length < 1)
return string.Empty;
Random rnd = new Random();
byte[] buffer = new byte[8];
ulong bit = 31;
ulong result = 0;
int index = 0;
StringBuilder sb = new StringBuilder((length / 5 + 1) * 5);
while (sb.Length < length)
{
rnd.NextBytes(buffer);
buffer[5] = buffer[6] = buffer[7] = 0x00;
result = BitConverter.ToUInt64(buffer, 0);
while (result > 0 && sb.Length < length)
{
index = (int)(bit & result);
sb.Append(key[index]);
result = result >> 5;
}
}
return sb.ToString();
}
/// <summary>
/// sha1加密算法
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string Sha1(string orgStr)
{
SHA1CryptoServiceProvider sHA1CryptoServiceProvider = new SHA1CryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(orgStr);
byte[] value = sHA1CryptoServiceProvider.ComputeHash(bytes);
sHA1CryptoServiceProvider.Dispose();
string text = BitConverter.ToString(value);
text = text.Replace("-", "");
return text.ToLower();
}
到这一步以及是产生了一个wx.config的配置类
接下来我们配置一下前端
public class ShineInLifeController : Controller
{
/// <summary>
///
/// </summary>
/// <returns></returns>
public ActionResult Index()
{
ViewBag.mode = new ShareHelper().CreateWxConfig(H5Helper.GetTicket(),"(提示)你的完整路径");
return View();
}
}
视图控制器写好了 我这里只做个例子
然后一进去视图就获取这些信息 调用微信的基础js 直接执行初始化
<script src="https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
(function () {
wx.config({
debug: false, // 开启调试模式
appId:'@wxConfig.appId', // 必填,公众号的唯一标识
timestamp: "@timestamp", // 必填,生成签名的时间戳
nonceStr: '@nonceStr', // 必填,生成签名的随机串
signature: '@signature',// 必填,签名,见附录1
jsApiList: ['onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
})();
</script>
然后再你需要的地方调用 就大功告成了
wx.ready(function () { //需在用户可能点击分享按钮前就先调用
wx.updateAppMessageShareData({
title: '', // 分享标题
desc: '', // 分享描述
link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
success: function () {
// 设置成功
}
})
});
第三步 看效果
差不多完成了 又到程序员快乐时光了 星期五 有没有小伙伴分享好玩的哈