自定义微信分享标题和描述信息

Posted 黄小墨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义微信分享标题和描述信息相关的知识,希望对你有一定的参考价值。

概述

环境: 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的Lib\\site-packages\\wfastcgi.py 放到你的项目下,跟 manage.py一个目录。

配置IIS:

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

image

可执行文件写: C:\\Python34\\python.exe|C:\\web\\jisuanqi\\wfastcgi.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:\\web\\jisuanqi

 

这个是settings.py所在的目录

Name: DJANGO_SETTINGS_MODULE
Value: jisuanqi.settings

 

添加完成后是这样的:

image

 

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

image

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

image


结束。

以上是关于自定义微信分享标题和描述信息的主要内容,如果未能解决你的问题,请参考以下文章

使用微信JSSDK自定义微信分享标题描述和图标

微信分享网页时自定义标题、描述和图片

微信小程序代码片段

微信内 H5 页面自定义分享

微信JSSDK自定义微信分享

如何控制微信分享网页时,展示的标题,描述和图片