首页 > 嗟来之食 > 【原创】.Net 微信 JS-SDK图片、语音上传接口的实现(MVC)-(一 、上传图片) – 。_莫思莫念莫路见、 –
2016
08-12

【原创】.Net 微信 JS-SDK图片、语音上传接口的实现(MVC)-(一 、上传图片) – 。_莫思莫念莫路见、 –

前段时间在做一个微信的项目,遇到了一个上传图片的问题,花了一下午,解决了这个问题,然后把总结出来的代码,分享了出来。
最近又有一个图片+语音的功能, 更是蛋疼, 本次采用的不是File文件上传,然后转码(Base64)的形式解决的,而是使用微信的开放Js-SDK实现的。
我们.net苦逼的很,微信官方的Demo上,有php、java、nodejs以及python的示例代码,就是没有我们.NET的,不知道大神们是不是都藏私了,现在大的不出来,做小的出来顶!d=====( ̄▽ ̄*)b
(开句玩笑话,别当真,鄙人菜鸟一枚)
闲话不聊, 马上进入正题
首先,我们看看官方给的 Js-SDK https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
…… 文档相信大家已经不陌生了,如何配置才是问题, 接下来,给大家详解 微信Js-SDK的调用(顺带给大家介绍下使用,老手可以直接跳过前戏~ 一、二、三、四)

第一步: 绑定域名
域名是指安全回调的域名 , 首先打开属于你的公众号,
点开 公众号设置 – 功能设置 – 设置安全回调域名
如图:

设置好安全回调的域名以后, 下面进入第二步

第二步: 引入JS-SDK文件
官方已经给出了地址, 我们直接在对应的页面中 引用这个JS即可, 这个JS里面的东西, 有微信已经封装好的交互(深究的话,鄙人暂时无能为力),直接引入即可

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> 类似这样的

第三步: 通过config接口注入权限验证配置
从这个时候开始, 我们就需要配置调用 JS-SDK里面的方法了;

所有需要使用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: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表, 可参考官方的目录,添加以后,可以使用该接口
});

下面是我在MVC里配置的代码附录

控制器端:

var appId = WeixinConfig.AppID;
var nonceStr = Util.CreateNonce_str();
var timestamp = Util.CreateTimestamp();
var domain = System.Configuration.ConfigurationManager.AppSettings["Domain"];
var url = domain + Request.Url.PathAndQuery;
var jsTickect = WeixinConfig.TokenHelper.GetJSTickect();
var string1 = "";
var signature = JSAPI.GetSignature(jsTickect, nonceStr, timestamp, url, out string1);
ViewBag.JSAPI = new JSSDKModel
{
appId = appId,
nonceStr = nonceStr,
signature = signature,
timestamp = timestamp,
string1 = string1,
};

@VIew页面端:

//配置微信
wx.config({
debug: false,
appId: '@ViewBag.JSAPI.appId', // 必填,公众号的唯一标识
timestamp: @ViewBag.JSAPI.timestamp, // 必填,生成签名的时间戳
nonceStr: '@ViewBag.JSAPI.nonceStr', // 必填,生成签名的随机串
signature: '@ViewBag.JSAPI.signature',// 必填,签名,见附录1
jsApiList: [
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'checkJsApi',
'startRecord',
'stopRecord',
'onVoiceRecordEnd',
'playVoice',
'pauseVoice',
'stopVoice',
'onVoicePlayEnd',
'uploadVoice',
'downloadVoice',
'getNetworkType'
]
});

配置完成后,我们进入第四步。

第四步: 接口验证
官方给的验证方法有 Ready 成功验证 和 Error 失败验证,下面我们看看代码

wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

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为调用的接口名
调用失败时:其值为具体错误信息

了解了以上信息以后,接下来就可以进入我们今天主要探讨的一个问题了&mdash;&mdash;微信的图片接口和语音接口

我们先看图片接口,然后一一实验

图像接口
拍照或从手机相册中选图接口
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
}
});
预览图片接口
wx.previewImage({
current: '', // 当前显示图片的http链接
urls: [] // 需要预览的图片http链接列表
});
上传图片接口
wx.uploadImage({
localId: '', // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (res) {
var serverId = res.serverId; // 返回图片的服务器端ID
}
});
备注:上传图片有效期3天,可用微信多媒体接口下载图片到自己的服务器,此处获得的 serverId 即 media_id。
下载图片接口
wx.downloadImage({
serverId: '', // 需要下载的图片的服务器端ID,由uploadImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (res) {
var localId = res.localId; // 返回图片下载后的本地ID
}
});

关于图片这边,微信官方提供了四大接口,分别是选择图片的接口, 这个选择类似于微信的图片选择,其实就是JS和微信的交互体验,

选择一个一个接口解释
选择图片接口
chooseImage
:在选择好图片以后,图片有一个localId返回,这个localId是微信缓存本地的一个ID,可以直接使用这个localId,进行图片显示,
例如: $("#img").append('<img src="'+localId+'" style="width:50px; height:50px;"/> <br />'); 这样的一句话,会在img标签里面,添加一张刚刚你选择的图片
预览图片接口
previewImage
:我们注意到,这个预览图片的接口,有两个参数, 一个是 current ,一个 urls , 这两个参数是什么意思呢? 首先, 不管是current 还是 urls , 里面的属性值, 都是http:// 的 需要预览的图片的地址, current 表示在调用这个接口时
会显示在第一页的图片, 而urls是表示,显示的图片集合 , 例如 :

var imgList = [
'http://h.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c70a6b76782d6277f9f2ff850.jpg',
];
wx.previewImage({
current: imgList[0],
urls: imgList
});

  
这样,当点击的事件触发到这个方法后,会调用这个预览接口,实现微信端看到的,点小图, 看到大图的效果

上传图片接口
uploadImage上传图片这个接口,很多人有这样的疑问(包括我第一次也是): 这个上传的图片在哪? 上传到哪儿了去了? 我们怎么才能用这个图片?接下来,我感同身受的,一个一个解决这个问题。疑: 上传的图片在哪里? – 答 : 我们注意到,之前在调用选择图片的接口的时候,有一个localId , 我解释过,是微信端缓存本地的一个图片编号,那么,我们联想一下, 这个localId ,是否就是选择得到的localId了, 没有错, 就是这个localId, 那也就是说,我们想要使用上传接口, 首先, 我们得选择图片,才能进行相应的上传操作。疑: 上传到哪儿去了? – 答: 当存在这个localId的时候,接口会找到相对应的图片上,然后把该图片,通过另一个接口 : https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE 上传至微信服务器的临时素材里面,当然,这个临时素材只有三天,并且有空间限制, 具体参考微信公众号里面的接口权限一栏 。疑: 我们怎么才能用这个图片? – 答: 当调用图片上传接口成功, 会有一个返回值返回给我们 ,类型是这样的- {"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789} ,我们需要注意到的有用的信息 就是这个 media_id ,这个media_id 表示我们所上传的素材, 在素材库里的位置, 当我们想要使用它的时候, 只需要把这个 media_id 还有 token 请求到素材请求的地址, 就可以得到使用这个素材了。
下载图片接口
downloadImage其实在上一个接口里面,稍稍已经提到过这个接口的使用, 没有错, 这个接口就是为了下载临时的素材,然后返回一个localId, 此时的localId, 是一个全新的, 代表的是下载到的图片的localId, 使用的方法也还是很简单, 通过一个 Src 属性即可使用讲到这里, 不得不停一下, 我们似乎忽略了些什么东西了,这些图片只能用三天,那三天后怎么办? 还有啊, 这个素材库有大小的限制, 不够了怎么办? 怎么办? 问我好咯, 我来分享一个办法&mdash;&mdash; 那就是转存到我们的服务器上, 微信已经替我们压缩了,我们下载下来, 然后转一下,送到我们自己的服务器上,留个地址,在我们的数据库存储一下, 一张可以持久高清无码图, 就这样被我们收入“囊中”。 下面继续贴代码, 看不懂的私聊,

<a href="javascript:void(0);" onclick="javascript:chooseImage();">选择图片</a>
<a href="javascript:void(0);" onclick="javascript:uploadImage();">图片上传</a>
<a href="javascript:void(0);" onclick="javascript:downloadImage();">图片下载</a>
<a href="javascript:void(0);" onclick="javascript:previewImage();">图片预览</a>
<div id="img">选择的图片</div>
<div id="img2"> 下载的图片</div>

<script type="text/javascript">
wx.config({
debug: false,
appId: '@ViewBag.JSAPI.appId', // 必填,公众号的唯一标识
timestamp: @ViewBag.JSAPI.timestamp, // 必填,生成签名的时间戳
nonceStr: '@ViewBag.JSAPI.nonceStr', // 必填,生成签名的随机串
signature: '@ViewBag.JSAPI.signature',// 必填,签名,见附录1
jsApiList: [
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'checkJsApi',
'startRecord',
'stopRecord',
'onVoiceRecordEnd',
'playVoice',
'pauseVoice',
'stopVoice',
'onVoicePlayEnd',
'uploadVoice',
'downloadVoice',
'getNetworkType'
]
});

wx.ready(function () {
//返回网络类型
wx.getNetworkType({
success: function (res) {
var networkType = res.networkType; // 返回网络类型2g,3g,4g,wifi
jQuery(function() {
$('#networkType').html(networkType);
});
}
});
});

// 5.1 拍照、本地选图
var images = {
localId: [],
serverId: []
};

function chooseImage() {
wx.chooseImage({
success: function (res) {
images.localId = res.localIds;
jQuery(function(){
$.each(res.localIds, function(i, n){
$("#img").append('<img src="'+n+'" style="width:50px; height:50px;"/> <br />');
});
});
}
});
}

// 5.2 图片预览
function previewImage()
{
var imgList = [
'http://h.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c70a6b76782d6277f9f2ff850.jpg',
];
wx.previewImage({
current: imgList[0],
urls: imgList
});
}

// 5.3 上传图片
var i = 0, length =0;
function uploadImage(){
if (images.localId.length == 0) {
alert('请先使用选择图片按钮');
return;
}
length= images.localId.length;
upload();
}

function upload() {
wx.uploadImage({
localId: images.localId[i],
success: function (res) {
i++;
//alert('已上传:' + i + '/' + length);
images.serverId.push(res.serverId);
$("#img2").append('<img src="'+res.localId+'" style="width:50px; height:50px;"/ /> <br />');
downloadImage(res.serverId);
if (i < length) {
upload();
}
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
}

//下载图片
function downloadImage(serverId)
{
$.get("@Url.Action("WeixinDownloadImage","Home")",{mediaId:serverId},function(data){
alert(data);
},"json")
}

wx.error(function (res) {
alert(res.errMsg);
});

</script>

  

注意到,我有定义一个全局变量, 可以拓展到多图上传, 还有一个递归的上传。 我先回去了,下班了,回家烧饭吃。

服务器端的,和语音的,下次再聊。

最后编辑:
作者:
这个作者貌似有点懒,什么都没有留下。

留下一个回复