参考:
wechatpy/app.py at master · jxtech/wechatpy
用代码:
#!/usr/bin/python # -*- coding: UTF-8 -*- from flask import Flask, g, request, make_response from wechat_sdk import WechatConf from wechat_sdk import WechatBasic from wechat_sdk.exceptions import ParseError app = Flask(__name__) app.debug=True wechatConf = WechatConf( token=’sipevents’, appid=’xxx’, appsecret=’yyy’, # 可选项:normal/compatible/safe,分别对应于 明文/兼容/安全 模式 encrypt_mode=’safe’, # 如果传入此值则必须保证同时传入 token, appid encoding_aes_key=’b7Nzzzzzzzzz2cLpt’ ) wechat = WechatBasic(conf=wechatConf) @app.route("/") def hello(): return "Hello SIPEvents!" @app.route(‘/wechat_auth’, methods=[‘GET’, ‘POST’]) def wechat_auth(): signature = request.args.get(‘signature’, ”) timestamp = request.args.get(‘timestamp’, ”) nonce = request.args.get(‘nonce’, ”) echostr = request.args.get(‘echostr’, ”) app.logger.debug(‘signature=%s, timestamp=%s, nonce=%s, echostr=%s’, signature, timestamp, nonce, echostr) if wechat.check_signature(signature, timestamp, nonce): app.logger.debug("wechat check_signature OK") if request.method == ‘GET’ : respStr = echostr app.logger.debug(‘respStr=%s’, respStr) return make_response(respStr) else : # for POST requestMethod = request.method app.logger.debug(‘requestMethod=%s’, requestMethod) # requestMethod=POST requestData = request.data app.logger.debug(‘requestData=%s’, requestData) # <xml> # <ToUserName><![CDATA[gh_ac090a9873a8]]></ToUserName> # <Encrypt><![CDATA[6PBVvYed+xxxxxxEu4MDYdYa8BXRYk1EtGpW0eDCiF/NLOyQzJsFM1T7jGsxjrKUIcYPmLFbNW8qZEIEDkAhahbVCI=]]></Encrypt> # </xml> # body_text = request.args.get(‘body’, ”) # app.logger.debug(‘body_text=%s’, body_text) try: wechat.parse_data(requestData) app.logger.debug(‘parse post body data OK’) except ParseError: app.logger.debug(‘parse body failed’) return make_response("current not support wechat auth POST") messageId = wechat.message.id # 对应于 XML 中的 MsgId messageTarget = wechat.message.target # 对应于 XML 中的 ToUserName messageSource = wechat.message.source # 对应于 XML 中的 FromUserName messageTime = wechat.message.time # 对应于 XML 中的 CreateTime messageType = wechat.message.type # 对应于 XML 中的 MsgType messageRaw = wechat.message.raw # 原始 XML 文本,方便进行其他分析 app.logger.debug(‘messageId=%s, messageTarget=%s, messageSource=%s, messageTime=%s, messageType=%s, messageRaw=%s’, messageId, messageTarget, messageSource, messageTime, messageType, messageRaw) if isinstance(wechat.message, TextMessage) : msgContent = wechat.message.content app.logger.debug(‘msgContent=%s’, msgContent) return make_response(msgContent) else : respStr = "Not Support type of POST" app.logger.debug(‘respStr=%s’, respStr) return make_response(respStr) else : app.logger.debug("wechat check_signature wrong") return make_response("wechat auth failed") if __name__ == ‘__main__’: app.run(debug=True) |
去在Flask下运行
结果解析body失败:
(SIPEvents) ➜ SIPEvents gunicorn -w 4 -b 127.0.0.1:8080 wechat_auth:app [2016-08-19 10:17:10 +0000] [29169] [INFO] Starting gunicorn 19.6.0 [2016-08-19 10:17:10 +0000] [29169] [INFO] Listening at: http://127.0.0.1:8080 (29169) [2016-08-19 10:17:10 +0000] [29169] [INFO] Using worker: sync [2016-08-19 10:17:10 +0000] [29174] [INFO] Booting worker with pid: 29174 [2016-08-19 10:17:10 +0000] [29175] [INFO] Booting worker with pid: 29175 [2016-08-19 10:17:10 +0000] [29178] [INFO] Booting worker with pid: 29178 [2016-08-19 10:17:10 +0000] [29179] [INFO] Booting worker with pid: 29179 <div–<—————————————————————————— DEBUG in wechat_auth [/usr/share/nginx/html/SIPEvents/wechat_auth.py:34]: signature=3b1370a65463c9cc9fc964f36ae05f6778cd2d18, timestamp=1471573034, nonce=2021984687, echostr= <div–<—————————————————————————— <div–<—————————————————————————— DEBUG in wechat_auth [/usr/share/nginx/html/SIPEvents/wechat_auth.py:37]: wechat check_signature OK <div–<—————————————————————————— <div–<—————————————————————————— DEBUG in wechat_auth [/usr/share/nginx/html/SIPEvents/wechat_auth.py:45]: requestMethod=POST <div–<—————————————————————————— <div–<—————————————————————————— DEBUG in wechat_auth [/usr/share/nginx/html/SIPEvents/wechat_auth.py:47]: requestData=<xml> <ToUserName><![CDATA[gh_ac090a9873a8]]></ToUserName> <Encrypt><![CDATA[3W7QxxxxxPHu0opmD6YAaw0fOKTcfzs/n4/Zd0ZShsb5Z1+S7qi1P0D1g==]]></Encrypt> </xml> <div–<—————————————————————————— <div–<—————————————————————————— DEBUG in wechat_auth [/usr/share/nginx/html/SIPEvents/wechat_auth.py:60]: parse body failed <div–<—————————————————————————— |
看起来像是:
在Flask中,
没搞懂如何获取POST的body内容
好像不是
requestData = request.data
搜:
Flask 获取 微信 Request body
python – Flask如何获取Post传过来的参数? – SegmentFault
Quickstart — Flask Documentation (0.11)
-》这个之前就看过了。
API — Flask Documentation (0.11)
里面有很多参数:
“Incoming Request Data
class flask.Request(environ, populate_request=True, shallow=False)
The request object used by default in Flask. Remembers the matched endpoint and view arguments.
It is what ends up as request. If you want to replace the request object used you can subclass this and set request_class to your subclass.
The request object is a Request subclass and provides all of the attributes Werkzeug defines plus a few Flask specific ones.
form
A MultiDict with the parsed form data from POST or PUT requests. Please keep in mind that file uploads will not end up here, but instead in the filesattribute.
args
A MultiDict with the parsed contents of the query string. (The part in the URL after the question mark).
values
A CombinedMultiDict with the contents of both form and args.
cookies
A dict with the contents of all cookies transmitted with the request.
stream
If the incoming form data was not encoded with a known mimetype the data is stored unmodified in this stream for consumption. Most of the time it is a better idea to use data which will give you that data as a string. The stream only returns the data once.
headers
The incoming request headers as a dictionary like object.
data
Contains the incoming request data as string in case it came with a mimetype Flask does not handle.
files
A MultiDict with files uploaded as part of a POST or PUT request. Each file is stored as FileStorage object. It basically behaves like a standard file object you know from Python, with the difference that it also has a save() function that can store the file on the filesystem.
environ
The underlying WSGI environment.
method
The current request method (POST, GET etc.)
path
full_path
script_root
url
base_url
url_root
Provides different ways to look at the current IRI. Imagine your application is listening on the following application root:
http://www.example.com/myapplication
And a user requests the following URI:
http://www.example.com/myapplication/%CF%80/page.html?x=y
In this case the values of the above mentioned attributes would be the following:
path u’/π/page.html’ full_path u’/π/page.html?x=y’ script_root u’/myapplication’ base_url url url_rootis_xhr
True if the request was triggered via a JavaScript XMLHttpRequest. This only works with libraries that support the X-Requested-With header and set it to XMLHttpRequest. Libraries that do that are prototype, jQuery and Mochikit and probably some more.
blueprint
The name of the current blueprint
endpoint
The endpoint that matched the request. This in combination with view_argscan be used to reconstruct the same or a modified URL. If an exception happened when matching, this will be None.
get_json(force=False, silent=False, cache=True)
Parses the incoming JSON request data and returns it. By default this function will return None if the mimetype is not application/json but this can be overridden by the force parameter. If parsing fails theon_json_loading_failed() method on the request object will be invoked.
Parameters:
- force – if set to True the mimetype is ignored.
- silent – if set to True this method will fail silently and return None.
- cache – if set to True the parsed JSON data is remembered on the request.
is_json
Indicates if this request is JSON or not. By default a request is considered to include JSON data if the mimetype is application/json or application/*+json.
New in version 0.11.
json
If the mimetype is application/json this will contain the parsed JSON data. Otherwise this will be None.
The get_json() method should be used instead.
max_content_length
Read-only view of the MAX_CONTENT_LENGTH config key.
module
The name of the current module if the request was dispatched to an actual module. This is deprecated functionality, use blueprints instead.
on_json_loading_failed(e)
Called if decoding of the JSON data failed. The return value of this method is used by get_json() when an error occurred. The default implementation just raises a BadRequest exception.
Changed in version 0.10: Removed buggy previous behavior of generating a random JSON response. If you want that behavior back you can trivially add it by subclassing.
New in version 0.8.
routing_exception = None
If matching the URL failed, this is the exception that will be raised / was raised as part of the request handling. This is usually a NotFound exception or something similar.
url_rule = None
The internal URL rule that matched the request. This can be useful to inspect which methods are allowed for the URL from a before/after handler (request.url_rule.methods) etc.
New in version 0.6.
view_args = None
A dict of view arguments that matched the request. If an exception happened when matching, this will be None.
”
自己去试试:
requestArgs = request.args app.logger.debug(‘requestArgs=%s’, requestArgs) |
输出:
requestArgs=ImmutableMultiDict([(‘nonce’, u’1438950245′), (‘openid’, u’oswjmv4X0cCXcfkIwjoDfCkeTVVY’), (‘signature’, u’cb962992182efd9f94f09560b893b20106408e49′), (‘timestamp’, u’1471573757′), (‘encrypt_type’, u’aes’), (‘msg_signature’, u’dc3336e6f85053f3563802f4e7b5398e3930d017′)]) |
-》
对于post的data,貌似还是需要自己去从:
requestData=<xml> <ToUserName><![CDATA[gh_ac090a9873a8]]></ToUserName> <Encrypt><![CDATA[XPWdOuDgWuyo7OkHmyE1+4168B1moD2BX55vjX9m1y2JuwLMOCvFh27iRq6vhDPIiOpLBmnHg3YTTg71qx02euJBLrMC7YjGyh18Qwr4NYt32Wnmdr4igCSg529yZBaqydkuXXZVGc2TawRN9hZ/1JxKR7vNFwB+XwIkPP/9vI45CQZym8cX6BGueOKyX4KIDqwAEa9NdEk35STgdHWrde/hcILi3pLKfLSvMHZ51/jMF1/N91zMvJWlcswII8MMgQ695Nl4TbtjKMia/TpSK4FI3e+N+mrQnfoZNA5W5inO3FaVYgZV593D6x8thOXEyfNOZajStsyImutaiJ3pPcJh08lIBc8J6Y1jGTCuER/ixZKRxYJjq3WAcPB/oR90ERbmggmstG6c3UIW3+mftQM2OaQqF3nWwnM+fxvRsFw=]]></Encrypt> </xml> |
提取对应的加了密的Encrypt原文?
如何获取 微信 Request body
快速上手 — wechat-python-sdk 0.5.9 文档
作者举例的代码:
# -*- coding: utf-8 -*- from wechat_sdk import WechatBasic # 下面这些变量均假设已由 Request 中提取完毕 token = ‘WECHAT_TOKEN’ # 你的微信 Token signature = ‘f24649c76c3f3d81b23c033da95a7a30cb7629cc’ # Request 中 GET 参数 signature timestamp = ‘1406799650’ # Request 中 GET 参数 timestamp nonce = ‘1505845280’ # Request 中 GET 参数 nonce # 用户的请求内容 (Request 中的 Body) # 请更改 body_text 的内容来测试下面代码的执行情况 body_text = """ <xml> <ToUserName><![CDATA[touser]]></ToUserName> <FromUserName><![CDATA[fromuser]]></FromUserName> <CreateTime>1405994593</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[wechat]]></Content> <MsgId>6038700799783131222</MsgId> </xml> """ # 实例化 wechat wechat = WechatBasic(token=token) # 对签名进行校验 if wechat.check_signature(signature=signature, timestamp=timestamp, nonce=nonce): # 对 XML 数据进行解析 (必要, 否则不可执行 response_text, response_image 等操作) wechat.parse_data(body_text) # 获得解析结果, message 为 WechatMessage 对象 (wechat_sdk.messages中定义) message = wechat.get_message() response = None if message.type == ‘text’: if message.content == ‘wechat’: response = wechat.response_text(u’^_^’) else: response = wechat.response_text(u’文字’) elif message.type == ‘image’: response = wechat.response_text(u’图片’) else: response = wechat.response_text(u’未知’) # 现在直接将 response 变量内容直接作为 HTTP Response 响应微信服务器即可,此处为了演示返回内容,直接将响应进行输出 print response |
中,body_text,就是我此处的
但是时没有加密的。。。
有很多字段:ToUserName,FromUserName,Content等
而我此处时加了密的:
只有两个字段ToUserName,Encrypt
看来需要自己去解密 解码?
wechat-sdk 0.4.2 : Python Package Index
[GOLANG]获取远程POST来的XML数据(微信公众平台)_葱烧烙饼_新浪博客
看wechat的sdk的源码:
wechat-python-sdk/basic.py at master · doraemonext/wechat-python-sdk
好像当是加密了safe模式时,必须要提供msg_signature,timestamp,nonce
???
那去试试:
[未解决]用Python的微信SDK wechat_sdk中parse_data时出错:ValidateSignatureError
然后加密的方式没有成功。
后来换成明文,可以了:
[已解决]尝试使用明文模式去测试微信的Python版的SDK wechat-sdk
转载请注明:在路上 » [已解决]Flask中如何获取微信POST发送过来的body的数据