微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。
将文件MP_verify_wah0fNzTG5YZlfMB.txt(点击下载) 放置在webapps 跟目下(springboot放置在resourece下即可)
先启动服务,然后再微信公众平台进行配置即可,成功的话 上面会显示 配置成功,我这里已经显示配置成功。
官方文档: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
目录
1 概述
1.1 JSSDK使用步骤
1.1.1 步骤一:绑定域名
1.1.2 步骤二:引入JS文件
1.1.3 步骤三:通过config接口注入权限验证配置
1.1.4 步骤四:通过ready接口处理成功验证
1.1.5 步骤五:通过error接口处理失败验证
1.2 接口调用说明
2 基础接口
2.1 判断当前客户端版本是否支持指定JS接口
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
备注:登录后可在“开发者中心”查看对应的接口权限。
在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.4.0.js
如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持>https)。
备注:支持使用 AMD/CMD 标准模块加载方法加载
直接在页面引用即可!
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"> </script>
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
注(以下方法逻辑必须放在服务器端,放置在域中在前台获取):
jsapi_ticket
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):…/15/54ce45d8d30b6bf6758f68d2e95bc627.html
2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value
对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
2.签名用的url必须是调用JS接口页面的完整URL。
3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
如出现invalid signature 等错误详见附录5常见错误及解决办法。
代码示例如下:
前提是access_token 已经获取,并且储存起来。
此代码直接复制即可 ( 出处: https://blog.csdn.net/u011327333/article/details/50439462 ) 稍加修改,感谢此博主!
获取
后台 controller
//微信jssdk 签名获取
@GetMapping("getSignature")
@ResponseBody
public String getSignature(String url) {
Map<String, String> sign = JsSignUtil.sign(url);
return JSON.toJSONString(sign);
}
@Slf4j
public class JsSignUtil {
public static Map<String, String> sign(String url) {
String jsapi_ticket = JsapiTicketTool.getTicket();
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
// string1 = "jsapi_ticket=" + jsapi_ticket +
// "&noncestr=" + nonce_str +
// "×tamp=" + timestamp +
// "&url=" + url;
string1 = getString1( nonce_str, timestamp, jsapi_ticket, url);
log.info("=========== 拼接的 参数 string1 = {}", string1);
signature = Sha1Util.getSha1(string1);
log.info("=========== 解密的 signature = {}", signature);
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
ret.put("appId", WeChatConfig.appid);
log.info("1.ticket(原始)=" + jsapi_ticket);
log.info("2.url=" + ret.get("url"));
log.info("3.jsapi_ticket(处理后)=" + ret.get("jsapi_ticket"));
log.info("4.nonceStr=" + ret.get("nonceStr"));
log.info("5.signature=" + ret.get("signature"));
log.info("6.timestamp=" + ret.get("timestamp"));
return ret;
}
public static String getSign(String jsapi_ticket, String noncestr, Long timestamp, String url)
throws NoSuchAlgorithmException {
String shaStr = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url="
+ url;
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(shaStr.getBytes());
StringBuffer signature = new StringBuffer();
for (int i = 0; i < result.length; i++) {
signature.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
}
return signature.toString();
}
private static String getString1(String nonce_str, String timestamp, String jsapi_ticket, String url){
//1.定义数组存放nonce_str,timestamp,jsapi_ticket,url
String[] arr = {"noncestr="+nonce_str,"timestamp="+timestamp,"jsapi_ticket="+jsapi_ticket,"url="+url};
//2.对数组进行排序
Arrays.sort(arr);
//3.生成字符串
StringBuffer sb = new StringBuffer();
for(String s : arr){
sb.append(s);
sb.append("&");
}
sb.deleteCharAt(sb.length()-1);
return sb.toString();
}
/**
* 随机加密
* @param hash
* @return
*/
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
/**
* 产生随机串--由程序自己随机产生
* @return
*/
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
/**
* 由程序自己获取当前时间
* @return
*/
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
/** 获取输入流
* 获取临时素材 调用js-sdk微信上传图片后下载临时素材
*/
public static InputStream getMediaStream(String mediaId) throws IOException {
String url = WeChatUrlParamConfig.LIN_SHI_IMG_URL;
String access_token = AccessTokenTool.getToken();
String params = "access_token=" + access_token + "&media_id=" + mediaId;
InputStream is = null;
try {
String urlNameString = url + "?" + params;
URL urlGet = new URL(urlNameString);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
http.connect();
// 获取文件转化为byte流
is = http.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
return is;
}
}
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
//1 如果在此处调用 拍照 ,支付 扫码等事件,会在页面加载时候进行弹出,调用js-sdk事件。
//2 如不需要的话,请在外面调用,通过点击事件调用即可。
});
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
接口调用说明
所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:
1.success:接口调用成功时执行的回调函数。
2.fail:接口调用失败时执行的回调函数。
3.complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
4.cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
5.trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。
备注:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。
以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:
调用成功时:“xxx:ok” ,其中xxx为调用的接口名
用户取消时:“xxx:cancel”,其中xxx为调用的接口名
调用失败时:其值为具体错误信息
在页面中调取js-sdk 微信原生接口时候,必须判断微信客户端版本信息是否支持。
wx.checkJsApi({
jsApiList: ['chooseImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res) {
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
备注:checkJsApi接口是客户端6.0.2新引入的一个预留接口,第一期开放的接口均可不使用checkJsApi来检测。
微信扫一扫
调起微信扫一扫接口
wx.scanQRCode({
needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
}
});
在页面中直接引用:
<script type="text/javascript">
$(document).ready(function () {
init();
});
var jsApiList = [
'checkJsApi',
'scanQRCode',
'chooseImage',
'uploadImage'
];
function init() {
alert("url = " + location.href.split("#")[0])
//获取签名
$.ajax({
url:"${ctx}/wechat/getSignature",
method:"post",
data:{url:location.href.split("#")[0]},
dataType: "json",
success:function (data) {
console.info("data = " , data);
var appId = data['appId'];
var timestamp = data['timestamp'];
var nonceStr = data['nonceStr'];
var signature = data['signature'];
//1 通过config接口注入权限验证配置
wx.config({
debug: true, /// // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId,
timestamp: timestamp,
nonceStr: nonceStr,
signature: signature,
jsApiList: jsApiList
});
//2 通过ready接口处理成功验证
wx.ready(function () {
//check client vserion wether support JS API
wx.checkJsApi({
jsApiList: ['scanQRCode'],
success: function (res) {
weui.alert("出错了:" + res.errMsg);
}
});
});
//3 通过error接口处理失败验证
//wrong error msg
wx.error(function (res) {
weui.alert("出错了请稍后再试!" + res.errMsg);
});
},
error:function (data) {
weui.alert("网络异常,请稍后再试。");
}
});
}
//scanning Qr code
function scanQRCodeFun() {
wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
// query invoices msg according scanning Qr code result
.... this is yourselef logic code ....
}
});
};
function photoFun() {
wx.chooseImage({
count: 1, // 最多可以选择的图片张数,默认9
sizeType: ['original', 'compressed'],//图片的类型:原图,压缩图
sourceType: ['album', 'camera'], //图片来源:相册,拍照
success: function (res) {
var localIds = res.localIds; // 返回选定照片的本地ID列表(手机上操作就是手机端的ID列表,是一个数组),localId可以作为img标签的src属性显示图片
wx.uploadImage({
localId: localIds[0], // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (result) {
var serverId = result.serverId; // 返回图片的服务器端ID
//................. 执行逻辑
},
error: function () {
}
});
},
fail: function () {
alert("图片识别错误,请稍后再试!");
},
complete: function () {
// alert("complete");
}, cancel: function () {
}
});
}
</script>
html页面
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0,viewport-fit=cover">
<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.0.0/weui.min.css">
<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js">script>
<script src="https://cdnjs.gtimg.com/cdnjs/libs/zepto/1.1.4/zepto.min.js">script>
<script src="https://res.wx.qq.com/open/libs/weuijs/1.1.4/weui.min.js">script>
<title>titletitle>
head>
<body ontouchstart>
<div class="weui-toptips weui-toptips_warn js_tooltips">错误提示div>
<div class="page">
<br>
<div class="page__bd page__bd_spacing">
<ul>
<li>
<div class="button-sp-area cell">
<br>
<button onclick="photoFun();" class="weui-btn weui-btn_block weui-btn_primary">拍照button>
<br>
<button onclick="scanQRCodeFun();" class="weui-btn weui-btn_block weui-btn_primary">扫码button>
<br>
div>
li>
ul>
div>
div>
<div class="weui-footer weui-footer_fixed-bottom">
<p class="weui-footer__text">Copyright © xxxxxx 有限公司p>
div>
div>
body>
更多js-sdk api接口 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115