简体   繁体   English

无法使用Elastic Beanstalk中的Flask读取JSON消息

[英]Unable to read JSON message using Flask from Elastic Beanstalk

I have a Python 'worker' using Elastic Beanstalk which reads messages from SQS. 我有一个使用Elastic Beanstalk的Python“工作者”,它从SQS读取消息。 This works fine, although the scaling is clunky as it is based on cpu. 尽管按比例缩放是基于cpu的笨拙操作,但效果很好。 Hence I'm trying to convert it to use AWS's new "Worker Tier Environment". 因此,我试图将其转换为使用AWS的新“ Worker Tier Environment”。

In at the deep end with Flask, but I have Flask running on an EB Work Tier. 在Flask的最深处,但我让Flask在EB Work层上运行。 At the moment it is set to simply log the message information that it receives - this is to make sure I can read the information before I move everything else over. 目前,它已设置为仅记录收到的消息信息-这是为了确保在我将所有其他信息移到其他位置之前,我可以阅读该信息。 Unfortunately I cannot see any sign of the message? 不幸的是我看不到任何消息迹象?

Here is my Flask test code: 这是我的Flask测试代码:

import logging
import logging.handlers

from flask import Flask, request

logfile = "/opt/python/log/scan.log"
mylog = logging.getLogger('helloworld')
# (for brevity, log format/config code removed)

application = Flask(__name__)
app = application
app.Debug=True

@app.route('/', methods=['POST'])
def hello():
    global mylog
    err = "Unrecognized method"
    mylog.warning("Hello called")

    request_detail = """
# Before Request #
request.endpoint: {request.endpoint}
request.method: {request.method}
request.view_args: {request.view_args}
request.args: {request.args}
request.form: {request.form}
request.user_agent: {request.user_agent}
request.files: {request.files}
request.is_xhr: {request.is_xhr}
## request.headers ##
{request.headers}
    """.format(request=request).strip()
    mylog.warning(request_detail)

    mylog.warning("Moreinfo:")

    mylog.warning("Args:")
    for k in request.args.keys():
        mylog.warning(k + ": "+request.args[k])
    mylog.warning("Form:")
    for k in request.form.keys():
        mylog.warning(k + ": "+request.form[k])
    mylog.warning("Files:"+len(request.files))
    for k in request.files.keys():
        mylog.warning(k + ": "+request.files[k])

    try:
        myJSON = request.get_json(force=True)
        if myJSON is None:
            mylog.warning("JSON could not be forced")
        else:
            mylog.warning("MyJSON size: " + len(myJSON))
            mylog.warning( "MyJSON: {myJSON}".format(myJSON=myJSON))
        if request.json is None:
            mylog.warning("NO JSON")
    except Exception as e:
        mylog.warning("Exception: " + e)

    # the code below is executed if the request method
    # was GET or the credentials were invalid
    mylog.warning("failure 404")
    return 'Failure: '+err , 404, {'Content-Type': 'text/plain'}


if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

Yes that big long format statement was borrowed from a book :-) 是的,那条长格式的声明是从书中借来的:-)

Here is a typical log output for a message: 这是消息的典型日志输出:

WARNING:2014-02-20 15:34:37,418: Hello called

WARNING:2014-02-20 15:34:37,419: 
# Before Request # 
request.endpoint: hello 
request.method: POST 
request.view_args: {} 
request.args: ImmutableMultiDict([])
request.form: ImmutableMultiDict([])
request.user_agent: aws-sqsd 
request.files: ImmutableMultiDict([])
request.is_xhr: False
## request.headers ## 
X-Aws-Sqsd-Msgid: 232eea42-5485-478c-a57f-4afddbf77ba9 
X-Aws-Sqsd-Receive-Count: 199 
X-Aws-Sqsd-Queue: #<AWS::SQS::Queue:0xb9255e90> 
Content-Length: 59 
User-Agent: aws-sqsd 
X-Aws-Sqsd-First-Received-At: 2014-02-20T13:55:34Z 
Host: localhost 
Content-Type: application/json

WARNING:2014-02-20 15:34:37,419: Moreinfo:

WARNING:2014-02-20 15:34:37,419: Args:

WARNING:2014-02-20 15:34:37,420: Form:

Note that none of the ImmutableMultiDict structures appear to have any keys. 请注意,ImmutableMultiDict结构似乎都没有任何键。 Also, none of the JSON methods/properties are returning anything. 同样,没有JSON方法/属性返回任何东西。

The Content-Length field does vary between log entries, so it does look like the information is there. 日志条目之间的Content-Length字段确实有所不同,因此看起来确实像其中的信息。 But how do I read it? 但是我该怎么读呢?

My JSON messages are written to SQS using BOTO, eg: 我的JSON消息使用BOTO写入SQS,例如:

  my_queue = conn.get_queue('my_queue_name')
  m = Message()
  m.set_body( json.dumps( my_structure ) )
  my_queue.write(m)

I also tried entering a raw JSON message by hand using the SQS web interface. 我还尝试使用SQS Web界面手动输入原始JSON消息。 This does not work either - I was speculating we might have a character encoding issue/ 这也不起作用-我推测我们可能会有字符编码问题/

It is not clear why your message logging is being cut off; 目前尚不清楚为什么您的消息记录被切断; perhaps you have an indentation error and part of your logging code is not considered part of the view method. 也许您有缩进错误,并且部分日志记录代码不被视为view方法的一部分。

However, if I understand you correctly, Boto SQS messages are not only encoded as JSON, the JSON message itself is also base64 encoded , which would mean that the flask.get_json() method won't decode it for you. 但是,如果我对您的理解正确,那么Boto SQS消息不仅会被编码为JSON,而且JSON消息本身也会被base64编码 ,这意味着flask.get_json()方法不会为您解码。

Instead, use the request.get_data() method to access the raw POST data and do the decoding yourself; 而是使用request.get_data()方法访问原始POST数据并自己进行解码; do first verify that the request.content_length value is within a tolerable size to prevent an attacker from sending you an overlarge message: 首先请确认request.content_length值在可容忍的范围内,以防止攻击者向您发送超大消息:

from flask import json
import base64

if request.mime_type == 'application/json' and request.content_length <= 1024**2:
    # message is JSON and smaller than 1 megabyte
    try:
        decoded = base64.b64decode(request.get_data())
        data = json.loads(decoded)
    except (ValueError, TypeError):
        mylog.exception('Failed to decode JSON')
    else:
        # do something with the decoded data

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM