前言
如果兄弟你有幸看到我的这篇关于微信分享自定义文字跟图标的文章还是对接不好,那基本上你是可以转行了!
环境准备
1.微信公众平台账号
2.公网服务器
开撸
1.注册微信公众平台账号
公众平台账号-注册/登录
2.修改基本配置
这里的url就是微信公众平台验证服务器调用我们自己的接口,并返回对应数据,这个会在后面说到!
这里的token自己随便设置,EncodingAESKey可以点击随机生成,加密方式自定义,我这里就选择明文!
这里先别点提交!还要准备服务器验证接口!
3.编写服务器检验接口
我这里使用java语言来编写的,随便创建一个springboot项目即可,打包后放入公网服务器
/**
*
* @param map
* @return 这个接口就是验证基本配置-->服务器配置-->修改配置,然而这个接口只需要返回入参的随机数echostr即可,没有其他操作可以不管
* @throws AesException
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
@RequestMapping("/wx")
public String wx(@RequestParam Map map) throws AesException, ParserConfigurationException, IOException, SAXException {
String encodingAesKey = "Io8tamQ1DIcshbxBAQN5CuW7kvw9Lk5IM3OT0Xbnwqf";
String token = "1qa2ws3ed";
String timestamp = "1409304348";
String nonce = "";
String appId = "wx6f7daa8eef26f28b";
String replyMsg = " 中文<xml><ToUserName><![CDATA[oia2TjjewbmiOUlr6X-1crbLOvLw]]></ToUserName><FromUserName><![CDATA[gh_7f083739789a]]></FromUserName><CreateTime>1407743423</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[eYJ1MbwPRJtOvIEabaxHs7TX2D-HV71s79GUxqdUkjm6Gs2Ed1KF3ulAOA9H1xG0]]></MediaId><Title><![CDATA[testCallBackReplyVideo]]></Title><Description><![CDATA[testCallBackReplyVideo]]></Description></Video></xml>";
nonce=map.get("nonce").toString();
timestamp=map.get("timestamp").toString();
String signature=map.get("signature").toString();
String echostr=map.get("echostr").toString();
log.error(String.valueOf(map.keySet()));
log.error(nonce);
log.error(signature);
log.error(echostr);
log.error(timestamp);
WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce);
System.out.println("加密后: " + mingwen);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(mingwen);
InputSource is = new InputSource(sr);
Document document = db.parse(is);
Element root = document.getDocumentElement();
NodeList nodelist1 = root.getElementsByTagName("Encrypt");
NodeList nodelist2 = root.getElementsByTagName("MsgSignature");
String encrypt = nodelist1.item(0).getTextContent();
String msgSignature = nodelist2.item(0).getTextContent();
String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
String fromXML = String.format(format, encrypt);
String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
System.out.println("解密后明文: " + result2);
return echostr;
}
如你直接的服务器域名为yyy.com,那么此时的微信公众平台校验的URL就是http://yyy.com/wx,这里要注意这个验证服务的端口只能是80或者443否者验证失败。
点击提交会显示验证成功!
4.设置JS安全域名
这里的域名就是你存放web界面的域名,如yyy.com
下载MP_verify_F1xFaqBnNbXRm1wn.txt次文件放到web服务器,我这里使用的nginx作为web服务器,那么这里就点恶心了,因为上面跑了一个java服务端口也是80,这里的nginx也是80,所以可以先关闭java服务
这里在j是安全域名配置点击保存是微信公众平台会到web服务器中校验MP_verify_F1xFaqBnNbXRm1wn.txt这个文件
到这一步的话微信公众平台的配置也就完成了,这里还需要在微信公众平台中取出appid,AppSecret,还有刚才配置的Token和随机生成的EncodingAESKey,这些数据都在基本配置里面!
开始正式编码
编写一个返回appid,timestamp,signature,nonceStr的接口
这里获取access_token和ticket请查看添加链接描述
这里获取jsapi_ticket请查看附录1-JS-SDK使用权限签名算法
这里有得到ticket后可以走微信官方的测试工具微信 JS 接口签名校验工具
H5端就可以使用界面上填入的noncestr,timestamp,生成的signature,和自己的appid完成微信分享自定义文字跟图标
JAVA后端生成noncestr、timestamp、signature,appid
//这个接口中的url可以有h5调用时将自己的界面路径上传给这个接口,前期测试可以写死
@RequestMapping("/getSignature")
public JSONObject getSignature(@RequestParam Map map) throws Exception {
String appid="你的appid";
String secret="你的AppSecret";
String grant_type="client_credential";//固定写死
String access_token="";//需要调用微信开放接口获取
String expires_in="";//需要调用微信开放接口获取
String ticket="";//需要调用微信开放接口获取
String url="http://yyy.com/index.html";//需要显示文字图片的地址
String nonceStr=getRandomStr();//随机数
String timestamp=getTimestamp();//获取时间戳-秒
Map<String, String> query = new HashMap<>();
query.put("grant_type", grant_type);
query.put("appid", appid);
query.put("secret", secret);
HttpResponse response = HttpUtils.doGet("https://api.weixin.qq.com", "/cgi-bin/token", "get", new HashMap<>(), query);
if (response.getStatusLine().getStatusCode() == 200) {
String json = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(json);
access_token = jsonObject.getString("access_token");
expires_in = jsonObject.getString("expires_in");
System.out.println(access_token);
System.out.println(expires_in);
}
Map<String, String> query2 = new HashMap<>();
query2.put("access_token", access_token);
query2.put("type", "jsapi");
HttpResponse response2 = HttpUtils.doGet("https://api.weixin.qq.com", "/cgi-bin/ticket/getticket", "get", new HashMap<>(), query2);
if (response2.getStatusLine().getStatusCode() == 200) {
String json = EntityUtils.toString(response2.getEntity());
JSONObject jsonObject = JSON.parseObject(json);
ticket = jsonObject.getString("ticket");
System.out.println(ticket);
}
String signature=getSHA1(ticket,timestamp,nonceStr,url);
JSONObject result=new JSONObject();
result.put("nonceStr",nonceStr);
result.put("timestamp",timestamp);
result.put("signature",signature);
result.put("appid",appid);
return result;
}
/**
* 进行sha1签名
* @param jsapi_ticket
* @param timestamp
* @param noncestr
* @param url
* @return 返回 signature
* @throws AesException
*/
public static String getSHA1(String jsapi_ticket, String timestamp, String noncestr, String url) throws AesException{
try {
StringBuffer sb = new StringBuffer();
sb.append("jsapi_ticket=").append(jsapi_ticket).append("&noncestr=").append(noncestr).append("×tamp=").append(timestamp).append("&url=").append(url);
String str = sb.toString();
System.err.println(str);
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
// 随机生成16位字符串
public static String getRandomStr() {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 16; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
//获取时间戳-秒
public static String getTimestamp() {
String startTs = String.valueOf(System.currentTimeMillis());
return startTs.substring(0,10);
}
HttpUtils
package com.example.demo.wx;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HttpUtils {
/**
* get
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @return
* @throws Exception
*/
public static HttpResponse doGet(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpGet request = new HttpGet(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
return httpClient.execute(request);
}
/**
* post form
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param bodys
* @return
* @throws Exception
*/
public static HttpResponse doPost(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
Map<String, String> bodys)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPost request = new HttpPost(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (bodys != null) {
List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
for (String key : bodys.keySet()) {
nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
}
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
request.setEntity(formEntity);
}
return httpClient.execute(request);
}
/**
* Post String
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPost(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
String body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPost request = new HttpPost(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (StringUtils.isNotBlank(body)) {
request.setEntity(new StringEntity(body, "utf-8"));
}
return httpClient.execute(request);
}
/**
* Post stream
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPost(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
byte[] body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPost request = new HttpPost(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (body != null) {
request.setEntity(new ByteArrayEntity(body));
}
return httpClient.execute(request);
}
/**
* Put String
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPut(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
String body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPut request = new HttpPut(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (StringUtils.isNotBlank(body)) {
request.setEntity(new StringEntity(body, "utf-8"));
}
return httpClient.execute(request);
}
/**
* Put stream
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPut(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
byte[] body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPut request = new HttpPut(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (body != null) {
request.setEntity(new ByteArrayEntity(body));
}
return httpClient.execute(request);
}
/**
* Delete
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @return
* @throws Exception
*/
public static HttpResponse doDelete(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
return httpClient.execute(request);
}
private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
StringBuilder sbUrl = new StringBuilder();
sbUrl.append(host);
if (!StringUtils.isBlank(path)) {
sbUrl.append(path);
}
if (null != querys) {
StringBuilder sbQuery = new StringBuilder();
for (Map.Entry<String, String> query : querys.entrySet()) {
if (0 < sbQuery.length()) {
sbQuery.append("&");
}
if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
sbQuery.append(query.getValue());
}
if (!StringUtils.isBlank(query.getKey())) {
sbQuery.append(query.getKey());
if (!StringUtils.isBlank(query.getValue())) {
sbQuery.append("=");
sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
}
}
}
if (0 < sbQuery.length()) {
sbUrl.append("?").append(sbQuery);
}
}
return sbUrl.toString();
}
private static HttpClient wrapClient(String host) {
HttpClient httpClient = new DefaultHttpClient();
if (host.startsWith("https://")) {
sslClient(httpClient);
}
return httpClient;
}
private static void sslClient(HttpClient httpClient) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] xcs, String str) {
}
public void checkServerTrusted(X509Certificate[] xcs, String str) {
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = httpClient.getConnectionManager();
SchemeRegistry registry = ccm.getSchemeRegistry();
registry.register(new Scheme("https", 443, ssf));
} catch (KeyManagementException ex) {
throw new RuntimeException(ex);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
}
}
编译打包放到公网服器
H5前端代码编写
<!DOCTYPE HTML>
<html>
<head>
<title>index</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1>yyy的网站测试</h1>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js" ></script>
<script type="text/javascript">
var appid = '';
var timestamp = '';
var nonceStr = '';
var signature = '';
var datePath = "http://xxxxx:xxxx/getSignature";
var xmlHttp = new XMLHttpRequest();
getDate();
function getDate() {
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
result = xmlHttp.responseText;
console.log("服务器res的数据:" + result)
//result自己转JSON一下
appid=result.appid;
timestamp =result.timestamp ;
nonceStr =result.nonceStr ;
signature =result.signature ;
}
}
xmlHttp.open("GET", datePath , true);
xmlHttp.send();
}
wx.config({
debug: false,
appId: appid,
timestamp: timestamp,
nonceStr: nonceStr,
signature: signature,
jsApiList: [
'updateAppMessageShareData'
]
});
wx.ready(function() {
//getDate();
wx.updateAppMessageShareData({
title: '分享标题分享标题分享标题', // 分享标题
desc: '我是描述我是描述我是描述我是描述我是描述我是描述我是描述我是描述我是描述', //
link: 'http://yyy.com/', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'http://yyy.com/test.png', // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
});
</script>
</body>
</html>
这是没有配置成功的
这是成功配置的
这里可以开启调试模式
wx.config({
debug: true,
appId: appid,
timestamp: timestamp,
nonceStr: nonceStr,
signature: signature,
jsApiList: [
'updateAppMessageShareData'
]
});
这里的调试模式就是微信的js-sdk中会弹窗,如果配置失败会弹窗显示invalidsignature,还有下一个弹窗也会提示另一个错误,这里其实想看到这个调试弹窗就要一定的运气了,不是将debug设置为true就一定会显示,当界面加载速度太快了,基本上是不会显示这个弹窗的,需要让界面响应速度变慢,这里就根据你们自己的h5经验来调试吧!我这里就是多请求几次后端服务器才模拟出加载速度慢的效果,也才看到这个弹窗,那么到这里如果还不是无法设置图片和描述,那么你真的可以转行了,最后吐槽一下腾讯的垃圾文档,跟坨屎一样!还有他们的这个微信公众平台也和坨屎样!尤其是他们的账号系统!