微信JS-SDK接口 + FLASK實現圖片上傳


 最近在做一個項目從全球各地采集圖片,考慮采用微信JS-SDK來簡化開發。圖片會首先上傳到微信的服務器,返回一個id,然后根據這個id去微信服務器獲取圖片。微信提供可選擇的壓縮圖片功能。圖片首先上傳到微信的服務器,可以保障較好的上傳穩定性。

詳細內容請參考微信的官方文檔:微信JS-SDK說明文檔

 

運行頁面如下

 

 

 

HTML

在微信demo的基礎上修改,見微信JS-SDK DEMO頁面

增加圖片的多次選擇,多次上傳,刪除等功能

 
         
uploadImage.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>圖片上傳 Demo</title>
    <link rel="stylesheet" href="http://203.195.235.76/jssdk/css/style.css">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
    <style>
        .box{ position:relative;width:97%;}
        input[type="checkbox"]{
             position:absolute; right:0px;
            -webkit-tap-highlight-color: rgba(0,0,0,0);
               -webkit-appearance: none;
            width: 24px;
            height: 24px;
            background-size: 100%;
            outline:none;
            background-image: url("data:image/png;base64,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");
        }
        img {
            height: auto;
            width: 100%;
        }
        .imgdiv {
            height: auto;
            width: 24%;
            float:left;
        }
    </style>
</head>
<body ontouchstart="">
<div class="wxapi_container">
    <div class="lbox_close wxapi_form">
        <h3 id="menu-image">已選擇圖片</h3>
        <div id="imgs"></div>
        <div style="clear:both"></div>
        <h3 id="upload-image">已上傳圖片</h3>
        <div id="uploadImgs"></div>
        <div style="clear:both"></div>
        <span class="desc">拍照或從手機相冊中選擇圖片</span>
        <button class="btn btn_primary" id="chooseImage">選擇圖片</button>
        <button class="btn btn_primary" id="uploadImage">上傳圖片</button>

        <button class="btn btn_primary" id="postData">提交</button>

    </div>
</div>
</body>
<script src="//cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript" charset="utf-8"
        src="demo.js"></script>
<script>

//配置微信
wx.config({
    debug: false, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。
    appId: '1234567890', // 必填,公眾號的唯一標識
    timestamp: {{ signature.timestamp }}, // 必填,生成簽名的時間戳
    nonceStr: '{{ signature.nonceStr }}', // 必填,生成簽名的隨機串
    signature: '{{ signature.signature }}',// 必填,簽名,見附錄1
    jsApiList: [ 'chooseImage', 'uploadImage'] // 必填,需要使用的JS接口列表,所有JS接口列表見微信sdk文檔附錄2
});
</script>
</html>
 
        

JS代碼

 

var images = {
        index:1,   //用於產生全局圖片id,綁定已選擇圖片和已上傳圖片
        selectIds: {},  //保存已經選擇的圖片id
        uploadIds:{}  //保存已經上傳到微信服務器的圖片
    };

    wx.ready(function () {
        // 5 圖片接口
        // 5.1 拍照、本地選圖
        $("#chooseImage").on("click", function () {
            wx.chooseImage({
                success: function (res) {
                    for (var i = 0; i < res.localIds.length; i++) {
                         //全局圖片id,綁定微信選擇圖片產生的localId,將用戶選擇圖片追加到已選擇圖片
                        var id = '' + images.index++; 
                        images.selectIds[id] = res.localIds[i];  
                        $('#imgs').append('<div class="imgdiv"><div class="box"><input id="' + id +'" type="checkbox"/><img src="' + res.localIds[i] + '" /></div></div>');
                    }
                    console.log('已選擇了 ' + Object.keys(images.selectIds).length + ' 張圖片');
                }
            });
        });

            // 5.3 上傳圖片
        $("#uploadImage").on("click", function () {
            if (Object.keys(images.selectIds).length == 0) {
                alert('請先選擇圖片');
                return;
            }
            var i = 0, length = Object.keys(images.selectIds).length;
            var selectIds = [];  //需要上傳的圖片的全局圖片id
            for(var id in images.selectIds){
                selectIds.push(id);
            }
            function upload() {
                wx.uploadImage({
                    localId: images.selectIds[selectIds[i]],  //根據全局圖片id獲取已選擇圖片
                    isShowProgressTips: 0, // 默認為1,顯示進度提示
                    success: function (res) {
                        //上傳成功,images.selectIds中移除,images.uploadIds追加
                        //圖片從已選擇移到已上傳區域
                        var selectId = selectIds[i];
                        localId = images.selectIds[selectId];
                        removeId(selectId);
                        $('#uploadImgs').append('<div class="imgdiv"><div class="box"><input id="' + selectId +'" type="checkbox"/><img src="' + localId + '" /></div></div>');
                        images.uploadIds[selectId] = res.serverId
                        i++;
                        if (i < length) {
                            console.log('已上傳成功 ' + i + '/' + length);
                            upload();
                        } else {
                            alert('圖片上傳完畢, 已上傳成功 ' + i + '/' + length);
                        }
                    },
                    fail: function (res) {
                        alert('上傳失敗 ' + i + '/' + length);
                    }
                });
            }
            upload();
        });
    });

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


    $('#postData').click(function () {
        if (Object.keys(images.uploadIds).length == 0) {
            alert('請先上傳圖片');
            return false;
        }

        var serverIds = [];
        for(var id in images.uploadIds){
            serverIds.push(images.uploadIds[id]);
        }
        var data = {
            'imgIds': serverIds
        }
        $.ajax({
            type: "post",
            async: false,
            url: '/uploadImgData',
            data: {data: JSON.stringify(data)},
            dataType: "json",
            success: function (res) {
                if (res.rc === 0) {
                     alert('提交成功!')
                } else {
                    alert(res.msg)
                }

            },
            error: function (e) {
                alert(JSON.stringify(e));
            }
        });
    });


$("body").on('click', ':checkbox', function(){
    var id = $(this).attr('id');
    removeId(id);
});

function removeId(id){
    if(id in images.selectIds){
        delete images.selectIds[id]
    }else{
        delete images.uploadIds[id]
    }
    $('#' + id).parent().parent().remove();
}

 

FLASK代碼

生成微信簽名,參考微信JSSDK文檔附錄1

生成簽名之前必須先了解一下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
@app.route('/uploadImgDemo', methods=['GET', 'POST'])
def uploadImgDemo():
    # if not in_weixin():
    #     return u'請在微信客戶端打開'
    now = int(time.time())
    noncestr = '%s' % time.time()
    url = request.url.decode('utf-8')
    jsapi_ticket = get_jsapi_ticket()  #用戶自定義函數,用於獲取jsapi_ticket 
    signature = 'jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s' % (jsapi_ticket, noncestr, now, url)
    m = hashlib.sha1()
    m.update(signature)
    signature = m.hexdigest()
    signature = {"timestamp": now, "nonceStr": noncestr, "signature": signature, "url": url}
    return render_template('uploadImage.html', signature=signature)

 

接受用戶提交的數據存到數據庫

 

@app.route('/uploadImgData', methods=['GET', 'POST'])
def uploadImgData():
    # if not in_weixin():
    #    return u'請在微信客戶端打開'
    try:
        data = request.form.get('data')
        if data:
            data = json.loads(data)
            if data.get('imgIds'):
                data['stamp'] = int(time.time())
                # db.image.insert(data)  #保存id到數據庫。
                return json.dumps({'rc': 0, 'msg': '上傳成功'})
        return json.dumps({'rc': 1, 'msg': '圖片不能為空'})
    except Exception as e:
        print e
        return json.dumps({'rc': 1, 'msg': '上傳失敗'})

 

圖片上傳到微信服務器后,用python下載圖片

 

access_token = None
def get_access_token(refresh = False):
    global access_token
    if not access_token or refresh:
        access_token = access_token() #用戶自定義函數,獲取access_token
    return access_token


#去微信服務器下載圖片
def downloadPic(img_dir, img_id):
    url = 'http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s' % (get_access_token(), img_id)
    down_file = '%s.jpg' % os.path.join(img_dir, img_id)
    with closing(requests.get(url, stream=True)) as r:
        content_length = int(r.headers.get('content-length', '0'))
        if 'content-disposition' in r.headers:
            m = re.match(r'attachment;\s*filename="(.*)"', r.headers.get('content-disposition'))
            if m:
                down_file = os.path.join(img_dir, m.group(1))
        if content_length < 1000:
            try:
                r_json = r.json()
                #提示access_token錯誤或過期,需要刷新token,重新下載
                if r_json.get('errcode') == 40001 or r_json.get('errcode') == 42001:
                    get_access_token(True)
                return False
            except Exception as e:
                print e
        with open(down_file, 'wb') as f:
            for data in r.iter_content(1024):
                f.write(data)
        return True

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM