cherrypy - 当 运行 使用 uWSGI 时,'module' 对象没有属性会话

cherrypy - 'module' object has no attribute session when run with uWSGI

我在亚马逊上使用 cherrypy 3.6.0、nginx 1.6.2 和 uWSGI 2.0.9 linux。

uwsgi.json 配置:

{
  "uwsgi": {
      "socket": ["127.0.0.1:8080"],
      "master": True,
      "processes": 1,
      "threads": 24,
      "uid": "ec2-user",
      "protocol": "http",
      "vacuum": True
      "chdir": "/usr/local/src/myapp",
      "wsgi-file": "/usr/local/src/myapp/wsgi.py",
      "logto": "/var/log/uwsgi.log"
  }
}

我尝试启用会话:

 cherrypy.config.update({
    'server.socket_host': '0.0.0.0',
    'engine.autoreload.on': False,
    'server.socket_port': 8080,
    'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
    'tools.sessions.on' : True,
    'tools.sessions.storage_type': "file",
    'tools.sessions.storage_path': "/home/ec2-user/.cherrypy_sessions",
    'tools.sessions.timeout': 60
})

在这里使用它们:

import cherrypy
import random
import string
import json
import urllib.parse


class IdentityApi(object):

@cherrypy.expose
def gen_crosssite(self):
    crsf = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(32))
    cherrypy.session['my_state'] = crsf;
    return json.dumps({'crsf': crsf})

我得到以下异常:

[25/Feb/2015:15:51:36] HTTP Traceback (most recent call last):
File "/usr/local/lib/python3.4/site-packages/cherrypy/_cprequest.py", line 670, in respond
response.body = self.handler()
File "/usr/local/lib/python3.4/site-packages/cherrypy/lib/encoding.py", line 217, in __call__
self.body = self.oldhandler(*args, **kwargs)
File "/usr/local/lib/python3.4/site-packages/cherrypy/_cpdispatch.py", line 61, in __call__
return self.callable(*self.args, **self.kwargs)
File "./api/IdentityApi.py", line 25, in gen_crsf
  cherrypy.session['my_state'] = crsf;
AttributeError: 'module' object has no attribute 'session'

更新:运行 它来自命令行 'python3 wsgi.py' 并且没有 uWSGI 工作。

不得不注释掉:

cherrypy.server.unsubscribe()
cherrypy.engine.start()

已更新 wsgi.py:

if __name__ == '__main__':
    cherrypy.log('jobtagr log file = %s', cherrypy.log.access_file)
    setup_logging()
    cherrypy.config.update({
        'server.socket_host': '0.0.0.0',
        'engine.autoreload.on': False,
        'server.socket_port': 8080,
        'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
        'tools.sessions.on' : True,
        'tools.sessions.storage_type': "file",
        'tools.sessions.storage_path': "/home/ec2-user/.cherrypy_sessions",
        'tools.sessions.timeout': 60
    })
    #    cherrypy.server.unsubscribe()
    #    cherrypy.engine.start()
    cherrypy.quickstart(application)

如何让会话在 uWSGI 下工作?

最近才出现这个错误,原来是我的uwsgi配置有问题。我建议检查您的 uwsgi 错误日志并将最后几行粘贴到此处。

这是我的配置文件;也许将它与你的进行比较,并确保你对每个值都有正确的值。

chdir=/root/Dropbox/QUTE_deployment
module=QUTE:app
master=True
vacuum=True
socket=/tmp/qute.sock
pidfile=/tmp/qute.pid
processes=1
threads=24
daemonize=/var/log/uwsgi.log
wsgi-file=/root/Dropbox/QUTE_deployment/QUTE.py

观察:

  1. cherrypy.session 属性不存在,除非 sessions.init 被会话工具调用,
  2. 不要混合全局(服务器、引擎)和应用程序(工具、调度)配置,
  3. 不要弄乱路由。您已经声明了 HTTP 动词调度,但我看到了非动词 gen_crosssite.

更新

我已经模拟了你的案例,现在看到了问题所在。这是记录在案的行为,但无论如何它都有点微妙。当您从更多演示的 cherrypy.quickstart 切换到使用 cherrypy.tree.mount 管理实际设置而不注意配置发生的情况时,就会发生这种情况。这里是cherrypy.quickstart,它很小:

def quickstart(root=None, script_name="", config=None):
    if config:
        _global_conf_alias.update(config)

    tree.mount(root, script_name, config)

    engine.signals.subscribe()
    engine.start()
    engine.block()

如您所见,它在 tree.mount 中设置了服务器(全局)配置和应用程序配置。这是 Basics 文档部分关于全局配置的警告:

cherrypy.config.update() is not meant to be used to configure the application. It is a common mistake. It is used to configure the server and engine.

这里是 Combined Configuration Files 部分:

If you are only deploying a single application, you can make a single config file that contains both global and app entries. Just stick the global entries into a config section named [global] (or top level key global), and pass the same file to both config.update and tree.mount. If you’re calling cherrypy.quickstart(app root, script name, config), it will pass the config to both places for you. But as soon as you decide to add another application to the same site, you need to separate the two config files/dicts.

这里是你的案例,用两个应用程序建模:

#!/usr/bin/env python3

import random
import string

import cherrypy


class Api:

  def __init__(self):
    self.string = String()
    # ...


class String:

  exposed = True


  def GET(self):
    return cherrypy.session.get('mystring', '')

  def POST(self, length=8):
    result = ''.join(random.sample(string.hexdigits, int(length)))
    cherrypy.session['mystring'] = result
    return result

  def PUT(self, new):
    cherrypy.session['mystring'] = new

  def DELETE(self):
    cherrypy.session.pop('mystring', None)


class Token:

  @cherrypy.expose
  def csrf(self):
    crsf = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(32))
    cherrypy.session['csrf'] = crsf
    return {'crsf': crsf}


if __name__ == '__main__':
  # global server config
  cherrypy.config.update({
    'server.socket_host' : '0.0.0.0',
    'server.socket_port' : 8080,
  })

  # applicaton config is provided
  cherrypy.tree.mount(Api(), '/api', {
    '/' : {
      'tools.sessions.on' : True,
      'request.dispatch'  : cherrypy.dispatch.MethodDispatcher(),
    },
    '/string' : {
      'tools.response_headers.on'      : True,
      'tools.response_headers.headers' : [('Content-Type', 'text/plain')]  
    }
  })

  # applicaton config is provided
  cherrypy.tree.mount(Token(), '/token', {'/' : {
    'tools.sessions.on' : True,
    'tools.json_out.on' : True,
  }})

  cherrypy.engine.signals.subscribe()
  cherrypy.engine.start()
  cherrypy.engine.block()