• linux+apache+mod_python+wechat_sdk搭建微信公共账号服务器


    linux+apache+mod_python+wechat_sdk搭建微信公共账号服务器

    转载请注明本文原作者:FignerLiu

    PRE

    最近尝试了下使用python搭建微信公共账号服务器,实现了简单的消息收发功能。其中遇到了很多问题,特此记录下来。

    服务器的选择

    如果使用python做开发语言,一般选用以下几种服务器可以用来做微信公共账号服务器(如果不全,欢迎大家补充):

    • SAE + wsgi
    • apache + mod_python
    • apache + mod_wsgi
    • nginx + wsgi

    如果对使用独立的服务器没有需求,或者对apache和nginx的配置不熟悉,一般采用SAE + wsgi做服务器。由于手头正好有闲置的Apache,本着生命在于折腾,从折腾中学习的目的,我选择了apache + mod_python作为我的服务器。以下的内容均以此为背景。
    在后面的开发过程中我体会到,我的这个选择绝对是最折腾人的 = 。=

    sdk的选择

    除了微信官方的sdk外,github上找到两个第三方sdk:

    • wechat-python-sdk
    • WeRoBot

    这两个sdk各有优劣,wechat-python-sdk代码更简洁易懂,而WeRoBot功能更全,包含微信支付API操作类等wechat-python-sdk不具有的功能。本次我选择使用了wechat-python-sdk

    服务器搭建与配置

    首先操作系统我选择的是放在阿里云上的centos 5.10
    需要安装如下软件包:

    • apache 我选用的是httpd-2.4.10
    • expat expat是用来解析xml等文件的库,我选用的是expat-2.0.1.tar.gz
    • apr Apache Portable Runtime我选用的是apr-1.5.1.tar.gz
    • apr-util 我选用的是apr-util-1.5.4.tar.gz
    • prce Perl Compatible Regular Expressions 我选用的是pcre-8.36.tar.gz 。 上述expat,apr,apr-util,prce均为安装Apache时的依赖项,注意各软件包的版本,如果不一致可能导致不兼容的问题。
    • mod_python Apache处理python的模块,我选用的是mod_python-3.5.0.tgz
    • python-devel mod_python的安装依赖项,我选用的是python-devel-2.6.6-52.el6.x86_64,应和系统使用的python版本一致。
    • python-pip python库安装工具,用来安装wechat-sdk
    • wechat-sdk 微信平台第三方sdk
    • virtualenv(可选) virtualenv的简介

      首先安装各软件包

      为了统一和方便,我把所有软件包都安装到了/usr/local下,均为编译安装。
      以下是部分安装配置命令
        #pcre
        ./configure --prefix=/usr/local/pcre
        #apr
        ./configure --prefix=/usr/local/apr
        #apr-util
        ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-expat=/usr/local/expat/
        #apache
        ./configure --prefix=/usr/local/apache --with-expat=/usr/local/epxat --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --with-pcre=/usr/local/pcre/
        或者
        ./configure --prefix=/usr/local/apache --with-expat=/usr/local/epxat --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --with-pcre=/usr/local/pcre/
        #mod_python
        ./configure --prefix=/usr/local/mod_python --with-apxs=/usr/local/apache/bin/apxs

    除wechat-sdk外,安装命令均为make && make install。wechat-sdk安装方法为pip install wechat-sdk

    配置apache

    首先将Apache配置为自启动服务,可参考这篇文章
    服务启动成功后,在浏览器输入你的服务器ip,可看到如下It works! 字样,则表示Apache安装成功。接下来修改Apache配置文件,打开文件/usr/local/apache/httpd.conf,分别在对应位置添加如下配置
    <Directory "/usr/local/apache/htdocs">下面添加

    <Directory "/usr/local/apache/htdocs/daemon/webchat">
        SetHandler mod_python
        PythonHandler index
        PythonDebug On
        Order allow,deny
        Allow from all
    </Directory>

    <IfModule alias_module>下面添加

    Alias /mywechat "/usr/local/apache/htdocs/daemon/webchat/mywechat.py"
    

    上面的配置的意思是:1.告诉Apache,目录/usr/local/apache/htdocs/daemon/webchat将使用mod_python处理客户端请求,所有请求交给这个目录下的index.py来处理;2.告诉Apache,为路径/usr/local/apache/htdocs/daemon/webchat/mywechat.py起了个别名,当客户端访问/mywechat的时候,实际上就是在访问/usr/local/apache/htdocs/daemon/webchat
    注,上述配置需要设置了DocumentRoot为/usr/local/apache/htdocs才有效

    功能开发

    接下来我们只需要向index.py和mywechat.py中添加对应的请求处理逻辑即可!
    我们实现最简单的功能,即接收服务器请求,并给客户端发送消息。
    要完成这一步,我们首先要了解我们都可能收到哪些请求,以及这些请求的作用。

    1. 首先在你登录微信公共账号,并点击成为开发者后,系统会让你验证你的服务器配置,这时微信公共平台服务器会向你的系统发送一个GET请求,来验证你的服务器,你需要按照微信制定的规则来返回验证信息。
    2. 当验证通过后,微信普通用户向你发送消息时,普通用户会发送给你的服务器一个POST请求,这个请求将请求内容包含在一个xml文档中。
      简单来说,你需要处理这两种正常请求。此外,在你公共账号投入商业使用之前,还需要能够处理别人伪造的非法请求,从而避免信息被窃取。

    示例代码

    index.py

    #encoding:utf-8
    from mod_python import apache
    import os
    def handler(req):
            handler = req.uri[req.uri.rfind('/')+1:]
            if handler[-3:] == ".py" :
                    handler = handler[0:-3]
            if not handler == "index" :
                    req.add_handler("PythonHandler", handler);
            else:
                    req.write("using the default handler  : index")
            return apache.OK

    mywechat.py

    # -*- coding: utf-8 -*-
    #!/usr/bin/python
    from mod_python import apache
    from mod_python import util
    import os
    from wechat_sdk import WechatBasic
    import sys
    import _apache
    parse_qsl = _apache.parse_qsl
    
    def handler(req):
            req.no_cache=True
            wechat = WechatBasic(token='yourtoken')
            if req.method == "GET":
                    req.content_type = "text/plain"
                    args=req.args
                    apache.log_error("get req caught!!!")
                    check(req,wechat)
            elif req.method == "POST":
                    req.content_type = "text/xml"
                    apache.log_error("post req caught!!!")
                    parse(req,wechat)
            else:
                    apache.log_error("unknown req method")
            return apache.OK
    
    def check(req,wechat):
            parameters = util.FieldStorage(req)
            apache.log_error(str(parameters))
            signature = parameters.get('signature',None)
            timestamp = parameters.get('timestamp',None)
            nonce = parameters.get('nonce',None)
            echostr = parameters.get('echostr','')
            if wechat.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
                    apache.log_error("check succeed")
                    req.write(echostr)
                    return apache.OK
            else:
                    apache.log_error("check failed")
                    return apache.HTTP_UNAUTHORIZED
    def parse(req,wechat):
            #get request body
            try:
                    clen = int(req.headers_in["content-length"])
            except (KeyError,ValueError):
                    raise apache.SERVER_RETURN(apache.HTTP_LENGTH_REQUIRED)
            req_body = req.read(clen)
            apache.log_error(req_body)
            #parse body
            try:
                    wechat.parse_data(req_body)
                    message = wechat.get_message()
                    response = None
                    if message.type == 'text':
                            if message.content == 'wechat':
                                    response = wechat.response_text('^_^')
                            else:
                                    text=u'text'
                                    response = wechat.response_text(text.encode('utf-8') + message.content.encode('utf-8'))
                    elif message.type == 'image':
                            response = wechat.response_text('image')
                    elif message.type == 'subscribe':
                            response = wechat.response_text('welcome to mywechat!!!')
                    else:
                            response = wechat.response_text('unknown'+message.type)
                    req.write(response)
                    apache.log_error(response)
            except Exception as e:
                    apache.log_error("
    
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    ")
                    apache.log_error(str(e))
                    apache.log_error("
    
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    ")

    这样简单的demo就Ok了!
    你可以拿起手机给自己的公共账号发消息来测试了!

    tips

    1. mod_python比较蛋疼的一个地方就是,很多时候出错了它在log里只说一句:Segment Fault.....,根本就没什么用,所以你需要在可能出现异常的地方将它们捕获,并用apache.log_error(str(e))将错误信息输出到log中。
    2. 实际安装过程中,遇到了很多由于expat不兼容而出现的问题,而官方又没有说明,所以我在这上面花了很多时间。实际上centos 5.10系统中预装了expat,但配置Apache安装项时,指定系统的expat的时候总会报错,所以决定自己编译安装expat。mod_python使用过程中,会加载pyexpat.so,而我的系统中pyexpat.so仅支持版本为2.0.1的expat。由于pyexpat.so为python安装包内的内容,我们无法更改,所以我们只能安装版本为2.0.1的expat来解决这个问题。
    3. 使用这种方式实际使用时我还遇到了这个错误“symbol XML_SetHashSalt, version EXPAT_2_0_1_RH not defined in file libexpat.so.1 with link time reference”,通过strings libexpat.so.1.5.2 |grep expat -i我发现我安装的expat中不包含“EXPAT_2_0_1_RH”这个字段,而系统自带的则包括。
      解决方法是
      cd d /usr/local/expat/lib
      ln -s /lib64/libexpat.so.1.5.2 libexpat.so.1.5.2
      
      这个解决方法很不漂亮,但是目前没找到别的解决办法。

    useful links

    1. 微信公共平台开发者文档
    2. 微信公众平台 Python 开发包文档
    3. modpython官方文档
    4. python_publisher对post请求content-type的限制
    5. logging with modpython
    6. 解决expat版本兼容问题IssuesWithExpatLibrary

    TODO

    文字编码问题还没有解决,当前环境无法给用户发送中文消息

  • 相关阅读:
    centos7安装Python3.7,执行./configure时报错,configure: error: no acceptable C compiler found in $PATH
    Hadoop集群搭建
    jdk安装
    ssh免密登陆
    centos安装python3.7
    centos7更改yum源
    32.Java基础_异常
    31.Java基础_日期/日期格式/日历类
    1.华为路由交换技术_网络基础知识
    396. 旋转函数(数学)
  • 原文地址:https://www.cnblogs.com/s0-0s/p/4008769.html
Copyright © 2020-2023  润新知