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("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n")
apache.log_error(str(e))
apache.log_error("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n")

这样简单的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

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

linux+apache+mod_python+wechat_sdk搭建微信公共账号服务器的更多相关文章

  1. 在SAE搭建微信公众账号服务

    让我们回到2014年11月,从公司请假回成都,在天府软件园B区旁边的小区里,那个10多平米的出租屋里,闲来无事,我想找个事情做一做,好让我这漂浮的心静下来.大约在半年前就申请了微信的一个公众账号,一直 ...

  2. Linux + Apache + PHP 环境搭建

    搭建环境: Ubuntu 15.04 Apache 2.4.16 PHP 5.6.15 1 安装Apache 先安装依赖程序(都安装在 /usr/local/ 目录下) apr-1.5.2.tar.g ...

  3. 微信公共账号开发:48001 api unauthorized解决

    微信公众平台开发:获取token成功并且拉取自定义菜单也OK,但是在拉取用户信息和分组信息 是总是出现这个 {"errcode":48001,"errmsg": ...

  4. UIWebView 需改userAgent 并且加载微信公共账号

    需要注意的是需要获取原来的UIWebView的User-Agent,然后拼接上自己新的User-Agent,貌似直接替换原来的无效,另外,修改User-Agent之后重新创建UIWebView加载网页 ...

  5. 如何在本地搭建微信小程序服务器

    现在开发需要购买服务器,价格还是有点贵的,可以花费小代价就可以搭建一个服务器,可以用来开发小程序,博客等. 1.域名(备案过的) 2.阿里云注册免费的https证书 3.配置本地的nginx 4.内网 ...

  6. ASP.NET MVC 微信公共平台开发之 微信接入

    ASP.NET MVC 接入微信公共平台 申请微信公共账号 既然要接入微信公共平台,微信公共号是必须的(当然如果只是测试的话也可以申请微信公共平台接口测试账号),来这里微信公共平台 申请微信公共号(注 ...

  7. Linux(CentOS)系统下搭建svn服务器

    由于GitHub的私有项目需要收费,gitlab对服务器的要求必须是4GB内存以上.对于一些个人的小型项目,想要免费的版本控制工具来管理自己的代码,又不想代码公开,无疑SVN是比较好的选择.windo ...

  8. Django + Apache + 树莓派 搭建内网微信公众号服务器

    其实早在微信开放公众号开发平台时就想弄一个自己的公众号服务器,奈何对web服务器搭建和开发一窍不通,只是注册了一下开发者帐号,并没有采取行动,万恶的拖延症. 前一年,开始接触python,打开了神奇世 ...

  9. 欢迎关注我的微信公众账号:Linux技巧(微信号:irefactoring),一起学习Linux知识~~~

    最近很少写博客了,一方面是近期工作比较繁忙,第二是把精力都放在GitHub和读源码去了. 申请了一个微信公众账号:Linux技巧 微信ID:irefactoring(意思是爱重构) ========= ...

随机推荐

  1. linux下安装Drcom

    环境:台式机物理机,centos7 因为要下载依赖包,物理机一开始没有网络,所以我先使用的是实验室的公用ip,然后完成以下操作(网上有大神说,可以现在其他机器上下载依赖包,copy过来也可以,但我没有 ...

  2. TypeScript完全解读(26课时)_汇总贴

    ECMAScript 6 入门:http://es6.ruanyifeng.com/ 官网:http://www.typescriptlang.org/ 中文网:https://www.tslang. ...

  3. 19.Consent视图制作

    新建consentController 继承Controller并引用命名空间 给他一个get的Action Index 添加一个Index的View 新建一个ConsentViewModel 再新建 ...

  4. [Lintcode]Word Squares(DFS|字符串)

    题意 略 分析 0.如果直接暴力1000^5会TLE,因此考虑剪枝 1.如果当前需要插入第i个单词,其剪枝如下 1.1 其前缀(0~i-1)已经知道,必定在前缀对应的集合中找 – 第一个词填了ball ...

  5. ZOJ2898【折半搜索】

    题意: 给出一系列值和对应的陷阱,对于陷阱如果存在两个就抵消,求价值最大. 思路: 折半枚举,利用异或 #include <bits/stdc++.h> using namespace s ...

  6. 机器学习中的L1、L2正则化

    目录 1. 什么是正则化?正则化有什么作用? 1.1 什么是正则化? 1.2 正则化有什么作用? 2. L1,L2正则化? 2.1 L1.L2范数 2.2 监督学习中的L1.L2正则化 3. L1.L ...

  7. TensorFlow中tf.ConfigProto()配置Sesion运算方式

    博主个人网站:https://chenzhen.online tf.configProto用于在创建Session的时候配置Session的运算方式,即使用GPU运算或CPU运算: 1. tf.Con ...

  8. 关于lspci命令

    lspci是一个用来查看系统中所有PCI总线以及连接到该总线上的设备的工具. 命令格式为 lspci -参数 (不加参数显示所有硬件设备) 至于有哪些参数及其详细用法可以看下这篇博客:http://w ...

  9. linux bg和fg命令

    linux下我们如果想一个任务或者程序还后台执行可以使用&,实际上linux还提供了其他任务调度的命令. bg将一个在后台暂停的命令,变成继续执行 fg将后台中的命令调至前台继续运行 jobs ...

  10. [TCP/IP]OSI七层模型和TCP/IP四层模型

    OSI參考模型 在過去的電腦網路上,由於資料通訊系統涉及複雜的軟硬體,可是又沒有統一的標準,導致通訊軟體不僅龐大複雜,而且不易測式.修改或分享.為此,ISO(國際標準組織)發展出一套OSI參考模型(O ...