微信开发引入sdk

2015-12-03 17:17:07 frankcheng5143 阅读数 68797

首先请阅读微信JS-SDK说明文档,了解微信JS的相关说明。
根据官方的使用步骤,关键的有以下几步

  1. 绑定域名(很关键
  2. 引入JS文件(很简单)
  3. 通过config接口注入权限验证配置(很重要
  4. 通过ready接口处理成功验证(还没用到)
  5. 通过error接口处理失败验证(还没用到)

绑定域名

绑定域名
如果域名绑定有误,会出现如下错误提示
错误的域名配置示例:

`http://gwchsk.imwork.net/wechat/order/test.html`

域名配置错误的提示信息:
{“errMsg”:”config:invalid url domain”}

这里写图片描述

所以,域名配置的时候一定要注意
1. 域名不要以http:开头
2. 域名不要配置到具体的页面
配置成功的提示如下

这里写图片描述

引入JS文件

一行代码就可以了

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

通过config接口注入权限验证配置

这一步非常重要,也是最关键的一步,这一部分
先看官方的示例

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

这里需要从服务器端网页面传递的参数有timestamp、nonceStr和signature而appId和jsApiList都是固定的,这里直接写在页面中。

首先,编写服务器端代码,生成timestampnonceStrsignature
在生成timestamp、nonceStr和signature的时候有两个参数需要获取
一个是access_token,另一个是jsapi_ticket

access_token的获取需要AppIdAppSecret,获取地址如下,发送GET请求

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

通过HttpClient发送http请求就可以获取到access_token

得到access_token之后,采用http GET方式请求获得jsapi_ticket

https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

注意,access_token和jsapi_ticket得有效期为7200秒,开发者必须在自己的服务全局缓存

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

签名算法

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

签名算法的实现

最难的就是签名算法的实现部分,幸好微信给了demo,网上好多人都在找,这里我把签名算法的实现贴出来,代码来自微信demo
这里写图片描述
下载地址
java代码如下,做了一点点修改

package com.gwc.wechat.utils.wechat;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class WxJSUtil {
    public static void main(String[] args) {

        // 注意 URL 一定要动态获取,不能 hardcode
        String url = "http://gwchsk.imwork.net/wechat/order/test.html";
        Map<String, String> ret = sign(url);
        for (Map.Entry entry : ret.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    };

    public static Map<String, String> sign(String url) {
        Map<String, String> ret = new HashMap<String, String>();
        //这里的jsapi_ticket是获取的jsapi_ticket。
        String jsapi_ticket = JSAPITicketTool.getTicket();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写,且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                  "&noncestr=" + nonce_str +
                  "&timestamp=" + timestamp +
                  "&url=" + url;
       // System.out.println(string1);

        try
        {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    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;
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

Controller的代码

@Controller
@RequestMapping(value = "/order")
public class OrderController {
@RequestMapping(value = "/test.html", method = RequestMethod.GET)
    public String testPage(Model model) {

        String url = Constant.AppURL + "/order/test.html";
        Map<String, String> ret = WxJSUtil.sign(url);
         for (Map.Entry entry : ret.entrySet()) {
                System.out.println(entry.getKey() + "=" + entry.getValue());
                model.addAttribute(entry.getKey().toString(), entry.getValue());
            }
        return "jqueryMobile";
    }
}

在Controller中将如下参数写进了jsp页面

    timestamp=1449132293
    nonceStr=fb4eaa58-6d53-40a8-a8fa-7033e9768a8a
    signature=7ad32da3f82cb36492de935a60727d3053d33f4b

其次编写jsp页面的代码
在jsp页面中需要将wx.config重的参数进行配置

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

在页面中读值

    <input id="timestamp" type="hidden" value="${timestamp}" />
    <input id="noncestr" type="hidden" value="${nonceStr}" />
    <input id="signature" type="hidden" value="${signature}" />

然后赋值

    <script type="text/javascript">
        $(function() {
            var timestamp = $("#timestamp").val();//时间戳
            var nonceStr = $("#noncestr").val();//随机串
            var signature = $("#signature").val();//签名
            wx.config({
                debug : true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                appId : 'wx622ca8545e5c354b', // 必填,公众号的唯一标识
                timestamp : timestamp, // 必填,生成签名的时间戳
                nonceStr : nonceStr, // 必填,生成签名的随机串
                signature : signature,// 必填,签名,见附录1
                jsApiList : [ 'scanQRCode' ]
            // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
            });
        });
    </script>

写一个按钮和输入框,将扫描的结果放进输入框

<input id="id_securityCode_input">
<button id="scanQRCode">扫码</button>

给按钮绑定事件,并执行微信扫码

$("#scanQRCode").click(function() {
            wx.scanQRCode({
                // 默认为0,扫描结果由微信处理,1则直接返回扫描结果
                needResult : 1,
                desc : 'scanQRCode desc',
                success : function(res) {
                    //扫码后获取结果参数赋值给Input
                    var url = res.resultStr;
                    //商品条形码,取","后面的
                    if(url.indexOf(",")>=0){
                        var tempArray = url.split(',');
                        var tempNum = tempArray[1];
                        $("#id_securityCode_input").val(tempNum);
                    }else{
                        $("#id_securityCode_input").val(url);
                    }
                }
            });
        });

运行结果如图
扫一包抽纸

抽纸

扫描结果

放进input

扫网址

这里写图片描述

这里写图片描述

微信JS-SDK中的扫一扫就基本实现了。

参考文献

微信JS-SDK说明文档
一篇博客

2017-12-18 10:40:22 OBKoro1 阅读数 28552

写在前面:

做微信的网页基本上都要接入微信的sdk,我在做的时候,也颇费了一番功夫,然后就想记录一下,供自己日后翻阅,以及让有需要的朋友可以做一下参考,如果喜欢的可以点波赞,或者关注一下,希望可以帮到大家。

本文首发于我的个人blog:obkoro1.com

安装sdk

    npm install weixin-js-sdk --save

开始之前大家可以先读一读微信公众号的 接入文档,vue是单页面项目,比如你想要接入微信分享功能,分享功能在每个路由地址都要有,因为每个路由的url是不一样的,搜易就需要在每个路由地址都引入一遍。

整体步骤:

  1. vue引入sdk的话,就是在路由组件里面的,组件生命周期的:creatd()和mounted()里面放代码。
  2. 用伪代码,熟悉一下整体的流程,要做哪些事情:

    //wx是引入的微信sdk
    wx.config('这里有一些参数');//通过config接口注入权限验证配置
    
    wx.ready(function() { //通过ready接口处理成功验证
    // config信息验证成功后会执行ready方法
        wx.onMenuShareAppMessage({ // 分享给朋友  ,在config里面填写需要使用的JS接口列表,然后这个方法才可以用 
            title: '这里是标题', // 分享标题
            desc: 'This is a test!', // 分享描述
            link: '链接', // 分享链接
            imgUrl: '图片', // 分享图标
            type: '', // 分享类型,music、video或link,不填默认为link
            dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
            success: function() {
                // 用户确认分享后执行的回调函数
            },
            cancel: function() {
                // 用户取消分享后执行的回调函数
            }
             });
            wx.onMenuShareTimeline({ //分享朋友圈
            title: '标题', // 分享标题
            link: '链接',
            imgUrl: '图片', // 分享图标
            success: function() {
                // 用户确认分享后执行的回调函数
            },
            cancel: function() {
                // 用户取消分享后执行的回调函数
            }
        });
    });
     wxx.error(function(res){//通过error接口处理失败验证
        // config信息验证失败会执行error函数
    });
    

上面的流程多看几遍,对整个流程有个概念,其中最重要的一步就是下面这个借口注入权限。

config接口注入权限

接入微信接口的最主要也是最重要一步步就是填写下面这些信息,填完这些信息之后,基本就好了。下面这些信息通常是通过后端接口来获取的。

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

获取config配置信息:

前端要获取上面那些信息,不用做太多东西,只要调后端接口就可以了。后端会把那些信息处理好,然后通过一个接口返给你这些参数。你要给后端传一个当前路由页面的完整url,后端就会返回上述的那些信息给你,后面就可以根据自己的需求调用相应的接口,自定义里面的东西。

坑点:url

这里要注意的就是url的问题,如果url没有正确传递,后端也会返回信息,但是签名信息会是错误的。

上面提到的完整url指的是:’http(s)://’部分,以及’?’后面的GET参数部分,但不包括’#’hash后面的部分。可以通过location.href来获取。

注意: 如果你的vue项目,路由没有开启history 模式,也就是你的url上面包含“#”,这个时候要从后端正确获取签名,就需要去掉url上#后面的字符。(url去掉’#’hash部分,可用location.href.split('#')[0]

封装调用sdk注入:

因为要在每个路由页面都注入sdk,这个肯定要复用的,不然那么多代码,看着就头大。

我是这么做的:

  1. 因为我把axios包了一层,然后把axios接口,在main.js里面挂载到Vue实例。
  2. 然后在全局函数里面调用这个接口,然后在每个路由页面的相应组件里面调用这个函数,把当前页面的url以及其他标题、图片什么的传进去。

里面的具体步骤就不说了,最重要的是参考上面的那个流程,函数里面的东西也都是基于那个流程的。

签名校验:

当你反复确认步骤都没有问题,微信sdk注入还是签名失败的时候,这个时候你就要考虑是不是后端那边的算法有问题,可以把后端返回的签名和微信提供的JS 接口签名校验工具生成的签名对比一下,或许是后端那边算法的问题也不一定。

后话

实不相瞒,当时我做的时候就是被url这个坑了,第一次做这个东西,没有经验,折腾了好久。引入sdk并不难,重要的是那个配置信息要填写正确,然后其他的就根据实际需求来做了。

最后:如需转载,请放上原文链接并署名。码字不易,感谢支持!本人写文章本着交流记录的心态,写的不好之处,不撕逼,但是欢迎指点。然后就是希望看完的朋友点个喜欢,也可以关注一下我。
个人blog and 掘金个人主页

以上2017.12.16

2018-03-19 18:35:31 museions 阅读数 3286

导:为确保能够正常的引入微信sdk,准备工作一定要做好!

准备:

1.vue cli项目准备,这个是前提条件。

在初始化vue项目后务必要将项目启动,项目依赖正常下载安装

2.假设已经可以启动vue项目了,接下来是下载 微信 sdk

npm install weixin-js-sdk --save

3.下载完成后需要引入到项目中

我的做法是全局引入微信sdk并且挂载到vue原型上。

以下是实现之前过程的代码:

vue init webpack wechatdemo

npm install

npm install weixin-js-sdk --save

npm run dev


//main.js
import wechat from './config/wechat'
Vue.prototype.$wechat = wechat;

2016-11-15 11:38:46 qq_24091555 阅读数 20260

           由于项目需要,需要接触微信开发,并要调用微信的JS-SDK里面的接口。

       因为经验缺乏,我百度一下关于微信开发的资料,但收集的资料都不尽人意。网上的主流的微信开发是采用PHP开发的,而本人学的Java。所以对PHP微信开发只能看懂思路。更有的是,网上一些微信开发视频,也是和PHP有关的,关于用Java开发的甚少。

       无奈之下,我只好苦啃微信开发文档。大家都知道,微信官方给的开发文档真的有点那个啥,一个功能实现非要分几个地方来说,看完这块,又得点击另一个页面看完另一块,甚是麻烦。这样的设定也让我走了好多坑。

但功夫不负有心,在研究透了微信开发文档之后,我顺利在在项目中完成微信开发。现在我将微信开发的经验分享一下,希望对大家有所帮助。

       微信JS-SDK是微信公众号平台面向网页开发这提供基于微信内的网页开发工具包。接口大类分为:基础接口、分享接口、图像接口、音频接口、智能接口、设备信息、地址位置、摇一摇周边、界面操作、微信扫一扫、微信小店、微信卡劵和微信支付。一般使用频率高的就是分享接口、地理微信、微信扫一扫和微信支付。

接下来,我将主要讲解如何调用微信分享接口。

第一步,准备内网映射工具,ngrok。不清楚这个的同学可以去百度一下。https://ngrok.com为ngrok官网。要进行微信开发,内网映射工具是不可少。毕竟,我们程序员进行开发,要测试开发的产品是否能用,都先在自己的电脑跑一下。但由于ngrok的服务器在外国的,鉴于天朝的墙太高,访问可能不稳定。所以我推荐的是国内的natapp,免费和收费的都有,服务毕竟稳定可靠,只不过要想自定义二级域名就得交费成为VIP咯。

第二步,配置JS接口安全域名。登录要进行开发的公众号,点击公众设置--->功能设置。设置JS接口安全域名,要注意三点:①填写域名前面不需加上http://,例如你的域名是http://test.com,直接填写test.com即可;②域名默认80端口,只支持80和443端口,所以域名后面不能添加端口号。③该域名为你调用微信JS-SDK接口域名。

第三步,引用JS文件。在需要调用JS接口的页面引入http://res.wx.qq.com/open/js/jweixin-1.0.0.js 。


第四步,通过config接口注入权限验证配置 。具体参数有什么用处,在截图都有注释讲解。其中jsApiList为我们要使用的接口,我在下面共引用了五个接口,分别为微信好友分享、QQ好友分享、腾讯微博分享、QQ空间分享和朋友圈分享。调用的都是分享的接口。至于其他接口列表,可以去微信开发文档那浏览一下。这里就不详说。

        第五步,在服务器生成相关参数传到调用JS-SDK页面,完成授权。这是最重要的一步。如上图所示,appId,timestamp,nonceStr,signature都为必填参数。下面我将会详细说说如何生成这些参数并传回页面。

appId为开发的微信公众号的AppID(应用ID),我们可以在登录微信公众号,在开发选项中点击基本配置来查看。

timestamp为系统生成的时间戳。


nonceStr为服务器随机生成的字符串。



signature为微信JS-SDK使用权限算法。在生成signature之前,我们要拿到jsapi_ticket。官方文档是这样解释的:


我们要注意三个地方。jsapi_ticket要缓存两个小时,每过两个小时,向微信那边请求一次。获取jsapi_ticket要通过access_token。那么我们该如何获取access_token呢?


从文档可以看出,access_token需要AppID和AppSercet两个参数。而且access_token和jsapi_ticket一样,有效期皆为两小时。这就要求我们服务器要缓存access_token和jsapi_ticket,当有效期一过,就重新请求。有的人采用是用数据库来存取这两个参数,而我采用的是用Quartz定时器。关于Quartz定时器的使用,可浏览我上篇博客《SSH与Quartz集成》,里面有关于Quartz的使用方法。

AppSercet可在与APPID同一页面获取。接下来,调用接口,获取access_token。



接下来,我们用access_token去获取jsapi_ticket。


获取jsapi_ticket,就可以进行生成签名。在此之前,先看一下官方文档的签名算法。



用代码实现。


第六步,传生成的参数给网页。



第七步,调用已授权的JS接口。


第八步,利用微信Web开发者工具调试,看看是否授权成功。(微信web开发者工具可在微信开发下载)。



2016-05-21 12:50:35 fengqingtao2008 阅读数 76653

      最近要在微信上做个问卷调查,有个上传图片功能,折腾找了半天资料,都不好弄,最终打算调用微信提供的上传图片接口,实现上传图片功能!此功能最大的好处是可以在微信服务器上暂存图片,减少本地服务器图片的缓存,等到最后的提交,在从微信提供的接口中下载图片到本地服务器中保存!

     微信JS-SDK说明文档

概述

微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

此文档面向网页开发者介绍微信JS-SDK如何使用及相关注意事项。

JSSDK使用步骤

步骤一:绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

步骤二:引入JS文件

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js

如需使用摇一摇周边功能,请引入 http://res.wx.qq.com/open/js/jweixin-1.1.0.js

备注:支持使用 AMD/CMD 标准模块加载方法加载

步骤三:通过config接口注入权限验证配置

所有需要使用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接口列表,所有JS接口列表见附录2

});

步骤四:通过ready接口处理成功验证

wx.ready(function(){

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

});

步骤五:通过error接口处理失败验证

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为调用的接口名

调用失败时:其值为具体错误信息

图像接口

拍照或从手机相册中选图接口

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后,进行权限验证配置,相关的参数值通过Ajax后台请求获取到

    $.ajax({
                url: "test.ashx",
                data: {
                    name: "GetWxJsApi",
                    curUrl: url
                },
                type: 'post',
                dataType: "json",
                success: function (data) {
                    if (data.success == "1") {

                        var timestamp = data.timestamp;
                        var noncestr = data.noncestr;
                        var signature = data.signature;
                        //通过config接口注入权限验证配置
                        wx.config({
                            debug: false,
                            appId: data.appId,
                            timestamp: timestamp.toString(),
                            nonceStr: noncestr,   //生成签名的随机串
                            signature: signature,  //签名
                            jsApiList: ['chooseImage', 'uploadImage', 'downloadImage']
                        });

                    } else {
                        alert(data.error);
                    }
                }
            });
验证通过后,可以调用手机选择图片接口

 //拍照或从手机相册中选图接口
        function wxChooseImage() {
            wx.chooseImage({
                count: 1,
                needResult: 1,
                sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
                sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
                success: function (data) {
                    localIds = data.localIds[0].toString(); // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
                    if (rh.tostr(localIds)) {
                        wxuploadImage(localIds);
                    }
                },
                fail: function (res) {
                    alterShowMessage("操作提示", JSON.stringify(res), "1", "确定", "", "", "");
                }

            });
        }
  选择图片成功后,同时调用上传图片接口,加载图片,主要要保存下mediaId字段

   备注:上传图片有效期3天,可用微信多媒体接口下载图片到自己的服务器!

//上传图片接口
        function wxuploadImage(e) {
           
            wx.uploadImage({
                localId: e, // 需要上传的图片的本地ID,由chooseImage接口获得
                isShowProgressTips: 1, // 默认为1,显示进度提示
                success: function (res) {
                    mediaId = res.serverId; // 返回图片的服务器端ID
                    if (rh.tostr(mediaId)) {
                        $(".myimg").attr("src", localIds);
                    }

                },
                fail: function (error) {
                    picPath = '';
                    localIds = '';
                    alert(Json.stringify(error));

                }

            });
        }
 最后正式入库的时候,要通过mediaId从腾讯服务器中,下载到本地服务器:

$.ajax({
                        url: "test.ashx",
                        data: {
                            name: "getPicInfo",
                            media: $.trim(mediaId)
                        },
                        type: "Get",
                        dataType: "text",
                        success: function (data) {
                            picPath = data;  //picPath 取得图片的路径
                          
                        },
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            alert("提交失败" + textStatus);
                        }

                    });
通过访问后台接口,同时也通过微信接口

var url = string.Format("https://api.weixin.qq.com/cgi-bin/media/get?access_token={0}&media_id={1}", token, media);
var PicPath = Common.GetWxPic(url, "").ToString();
<pre name="code" class="csharp"> public static string GetWxPic(string url,string data)
        {
            string path = "";
            try
            {
                ServicePointManager.Expect100Continue = false;
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + (data == "" ? "" : "?" + data));
                request.Method = "GET";
                
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    if(response.StatusCode  == HttpStatusCode.OK)
                    {
                        string fileName = Common.RightStr(response.Headers["Content-disposition"],"filename=",false).Replace("\"","");
                        path = "/uploadfile/" + fileName;
                        
                        Stream responseStream = response.GetResponseStream();
                        BinaryReader br = new BinaryReader(responseStream);
                        
                        FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(path), FileMode.Create, FileAccess.Write);

                        const int buffsize = 1024;
                        byte[] bytes = new byte[buffsize];
                        int totalread = 0;

                        int numread = buffsize;
                        while (numread != 0)
                        {
                            // read from source
                            numread = br.Read(bytes, 0, buffsize);
                            totalread += numread;

                            // write to disk
                            fs.Write(bytes, 0, numread);
                        }

                        br.Close();
                        fs.Close();

                        response.Close();

                    }
                    else
                    {
                        response.Close();
                        path = "";
                    }
                    
                }
            }
            catch (Exception)
            {
                path = "";
            }
            return path;
        }



保存图片到本地服务器上,即可:



完整代码下载