zoukankan      html  css  js  c++  java
  • 自定义微信分享标题和描述信息

    概述

    环境: python3.4, Django1.9.6

    准备工作

    首先要搞到微信公众平台开发者ID和开发者密码,这个在公众号平台的公众号开发信息里查看和修改

    image

    然后在IP白名单中,把服务器的IP加进去。

    最后在公众号设置--功能设置里 把域名加进去

    image

    添加域名的时候,会看到提示下载一个txt文件,放到web服务器;这里我是把它放在static目录下,然后给它单独做了个url,单独写了view访问。

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^$', views.index),
        url(r'^MP_verify_xdl1MStBzOrk6qLu.txt', views.gettxt),
    ]
    def gettxt(request):
        with open('MP_verify_xdl1MStBzOrk6qLu.txt', 'r') as f:
            return HttpResponse(f.read())

    这样是为了http://你的域名/MP_verify_xdl1MStBzOrk6qLu.txt可以访问到它。

    当然直接把它放到nginx根目录下也可以,我是在IIS下配置的站点,其实不写路由不写views也是可以的,详细见最后的部署

    基本流程

    基本流程步骤如下:

    1. 通过开发者ID和密码 获取到 token

    2. 通过token获取到ticket

    3. 拿到ticket生成签名

    4. 后台返回数据给前台js调用

    注意的是token和ticket是2个小时过期,而且api每天有请求次数,所以我们要把ticket存到本地,过期后再去请求。

    代码

    settings.py  我只列出比较重要的内容

    STATIC_URL = '/static/'
    
    STATIC_ROOT = os.path.join(BASE_DIR,  'static')
    TEMPLATE_DIRS = (
        os.path.join(BASE_DIR,  'templates'),
        'app',
    )
    
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'static'),
    )
    
    #微信API信息
    WEIXINAPI = {
        "tokenUrl": "https://api.weixin.qq.com/cgi-bin/token?",
        "ticketUrl": "https://api.weixin.qq.com/cgi-bin/ticket/getticket?",
        "appID": "开发者ID",
        "appwd": "开发者密码"
    }
    
    #分享页面信息
    PAGEINFO = {
        "Title": "这里是标题信息",
        "Description": "这里是描述信息",
        "PicUrl": "这里是你要分享的url"
    }

    views.py

    我是图省事把所有代码都写在views.py里了,其实这些可以写到别的文件里,然后import进来,views.py只写它该写的东西 

    先写一个获取token的方法:

    def flush_token():
        token_url = settings.WEIXINAPI["tokenUrl"]
        appID = settings.WEIXINAPI["appID"]
        appwd = settings.WEIXINAPI["appwd"]
        url = "%sgrant_type=client_credential&appid=%s&secret=%s" % (token_url, appID, appwd)
        ssl._create_default_https_context = ssl._create_unverified_context
        jsondata = urllib.request.urlopen(url).read().decode()
        json_dic = json.loads(jsondata)
        return json_dic["access_token"]

    再来写一个获取ticket的方法

    def flush_ticket(access_token):
        ticket_url = settings.WEIXINAPI["ticketUrl"]
        url = '%saccess_token=%s&type=jsapi' % (ticket_url, access_token)
        jsondata = urllib.request.urlopen(url).read().decode()
        json_dic = json.loads(jsondata)
        json_dic["expires_time"] = time.time()
        with open("ticket.txt", 'w') as f:
            json.dump(json_dic, f)
        return json_dic["ticket"]

    因为每次分享的时候,ticket要先从ticket.txt中获取,然后对比当前时间,如果超过两个小时了,需要更新;没有超过,则直接使用,那就写一个get_ticket方法:

    def get_ticket():
        if os.path.exists("ticket.txt"):
            with open('ticket.txt', 'r') as f:
                ticket_dic = json.load(f)
            expires_time = ticket_dic['expires_time']
            now_time = time.time()
            if now_time - expires_time >= 7200:
                #更新ticket
                access_token = flush_token()
                ticket = flush_ticket(access_token)
            else:
                ticket = ticket_dic["ticket"]
        else:
            access_token = flush_token()
            ticket = flush_ticket(access_token)
        return ticket

    获取到ticket之后,就要生成签名信息了, 签名信息需要几个参数,一个是16位的随机字符串,一个是ticket, 一个是timestamp这的单位是秒, 最后一个是你要分享的url, 然后将它们按照ASCII码由小到大的顺序以url参数方式拼接起来 用sha1加密。

    先写一个生成随机数的方法:

    def randomone(n):
        string = ''
        if n.isdigit():
            for i in range(int(n)):
                if i%2 != 0:
                    tmp = random.randint(0,9)
                else:
                    tmp = str(chr(random.randint(97, 122)))
                string = "%s%s" % (string, tmp)
        return string

    现在再来一个生成签名的方法:

    def create_string(url):
        random_string = randomone('16')
        times = int(time.time()/1000)
        ticket = get_ticket()
        arg_string = "jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s" % (ticket, random_string, times, url)
        m = hashlib.sha1()
        m.update(arg_string.encode('utf8'))
        sign = m.hexdigest()
        return times,random_string,sign

    这个方法返回了三个变量,这三个变量是时间,随机字符串,和签名信息;这三个变量需要传递给前台页面使用。

    最后来写一个index方法:

    ef index(request):
        url = request.get_host() + request.get_full_path()
        url = 'http://%s' % url
        appId = settings.WEIXINAPI["appID"]
        timestamp, nonceStr, signature = create_string(url)
        title = settings.PAGEINFO["Title"]
        des = settings.PAGEINFO["Description"]
        picture = settings.PAGEINFO["PicUrl"]
    
        return render(request, 'index.html', locals())

    注意这里,在获取URL的时候,如果你的url只是个域名,浏览器会自动在域名后面加上“/”,比如http://www.qq.com/ , 最后这个”/”也是要参与加密的; 如果你的url还有参数,可能还会自动在后面加上#weixin啥的,都要去掉,具体把url打印出来看就知道了。

    代码部分到这里就结束了。下面看页面和js.

    前台页面和js

    我直接把js写到页面上了,你也可以写到独立的js文件中,用到的变量以参数形式传过去,在页面上调用即可。

    我写在了head标签里

    首先引一个weixin的js:

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

    然后写一下xw.config

    wx.config({
                debug: false,
                appId: '{{ appId }}',
                timestamp: '{{ timestamp }}',
                nonceStr: '{{ nonceStr }}',
                signature: '{{ signature }}',
                jsApiList: [
                    // 所有要调用的 API 都要加到这个列表中
                    'checkJsApi',
                    'openLocation',
                    'getLocation',
                    'onMenuShareTimeline',
                    'onMenuShareAppMessage',
                    'onMenuShareQQ',
                    'onMenuShareWeibo'
                  ]
            });

    最后把各个分享方法写到wx.ready()方法里,意思是文档加载完后就加载它们

    wx.ready(function () {
    
                  //分享给朋友
                    wx.onMenuShareAppMessage({
                      title: '{{ title }}',
                      desc: '{{ des }}',
                      link: '{{ url }}',
                      imgUrl: '{{ picture }}',
                      trigger: function (res) {
                        // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
                        //alert('用户点击发送给朋友');
                      },
                      success: function (res) {
                        alert('已分享');
                      },
                      cancel: function (res) {
                        alert('已取消');
                      },
                      fail: function (res) {
                        alert(JSON.stringify(res));
                      }
                    });
    
                    //分享到朋友圈
                    wx.onMenuShareTimeline({
                      title: '{{ title }}',
                      link: '{{ url }}',
                      imgUrl: '{{ picture }}',
                      trigger: function (res) {
                        // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
                        //alert('用户点击分享到朋友圈');
                      },
                      success: function (res) {
                        alert('已分享');
                      },
                      cancel: function (res) {
                        alert('已取消');
                      },
                      fail: function (res) {
                        alert(JSON.stringify(res));
                      }
                    });
    
                    //分享到QQ
                    wx.onMenuShareQQ({
                      title: '{{ title }}',
                      desc: '{{ des }}',
                      link: '{{ url }}',
                      imgUrl: '{{ picture }}',
                      trigger: function (res) {
                        // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
                        //alert('用户点击分享到朋友圈');
                      },
                      success: function (res) {
                        alert('已分享');
                      },
                      cancel: function (res) {
                        alert('已取消');
                      },
                      fail: function (res) {
                        alert(JSON.stringify(res));
                      }
                    });
    
                     //分享到腾讯微博
                    wx.onMenuShareWeibo({
                      title: '{{ title }}',
                      desc: '{{ des }}',
                      link: '{{ url }}',
                      imgUrl: '{{ picture }}',
                      trigger: function (res) {
                        // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
                        //alert('用户点击分享到朋友圈');
                      },
                      success: function (res) {
                        alert('已分享');
                      },
                      cancel: function (res) {
                        alert('已取消');
                      },
                      fail: function (res) {
                        alert(JSON.stringify(res));
                      }
                    });
            });

    上面那些alert() 都可以注释掉,没啥用,反而会影响用户体验,因为本身就会有个已分享的提示,不需要自己写。

    到这就写完了,需要说的是,这个要在微信时打开链接,然后右上角的‘…’, 选择分享, 效果是这样的:

    image

     

    IIS下部署Django

    安装IIS的时候,需要把CGI装上

    image

    然后安装 wfastcgi:

    pip install wfastcgi

    安装完成之后将 python的Libsite-packageswfastcgi.py 放到你的项目下,跟 manage.py一个目录。

    配置IIS:

    选中你的站点,选择”处理程序映射”, 添加模块映射:

    image

    可执行文件写: C:Python34python.exe|C:webjisuanqiwfastcgi.py 中间用”|”分隔,前面是python的路径,后面是刚才wfastcgi.py文件的路径,然后点击“请求限制”:

    image

    去掉这个 勾。

    最后选中 web服务器的 fastCGI设置

    image

    选中新建的应用程序,点击编辑,添加三个环境变量:

    get_wsgi_application()方法的位置

    Name: WSGI_HANDLER
    Value: django.core.wsgi.get_wsgi_application()

    Django项目目录,就是manage.py所在的目录,我的项目名称叫jisuanqi

    Name: PYTHONPATH
    Value: D:webjisuanqi

    这个是settings.py所在的目录

    Name: DJANGO_SETTINGS_MODULE
    Value: jisuanqi.settings

    添加完成后是这样的:

    image

    到这就可以访问到网站了,但是会发现静态文件,所有的css,js,图片全丢了,访问不到;解决方法也很简单,把这些文件交给IIS处理就好了。

    image

    选中static目录,进入 处理程序映射。把“DjangoWebHandller”删掉就行了。

    image


    结束。

  • 相关阅读:
    让WPF和SL控件同时支持绑定和赋值
    VS2010下如何调试Framework源代码(即FCL)
    使用Entity Framework和WCF Ria Services开发SilverLight之2:POCO
    WPF快速指导15:动画
    改善C#程序的建议5:引用类型赋值为null与加速垃圾回收
    使用Entity Framework和WCF Ria Services开发SilverLight之1:简单模型
    MVVM中的命令绑定及命令参数
    改善C#程序的建议7:正确停止线程
    Prism安装、MVVM基础概念及一个简单的样例
    改善C#程序的建议8:避免锁定不恰当的同步对象
  • 原文地址:https://www.cnblogs.com/huangxm/p/8419249.html
Copyright © 2011-2022 走看看