使用cherrypy wsgi服务器的有趣错误

时间:2013-11-20 07:23:21

标签: django wsgi cherrypy

我正在使用cherrypy的wsgi服务器为我的django项目提供服务。服务器提供来自django项目的所有静态和媒体文件。代码如下

#create basic django WSGI app
app = WSGIHandler()
path = {'/': app}

#create app that handles static files from static root and put it in path
path[static_url] = StaticFileWsgiApplication(static_root)

#create app that handles /media and put it in path
path[media_url] = StaticFileWsgiApplication(media_root)

#dispatch the applications
dispatcher = wsgiserver.WSGIPathInfoDispatcher(path)

if __name__ == '__main__':
    print 'Close window to exit'

    #create wsgi cherrypy server
    server = wsgiserver.CherryPyWSGIServer(
        ('0.0.0.0', 8000),
        dispatcher,
        server_name='cherrypy-django',
        numthreads=20
    )
    try:
        server.start()
    except KeyboardInterrupt:
        server.stop()

和静态文件应用

class StaticFileWsgiApplication(object):

    #init function to get the directory of collectstatic (STATIC_ROOT)
    def __init__(self, static_file_root):
        self.static_file_root = os.path.normpath(static_file_root)

    #Every wsgi app must be callable. It needs 2 arguments
    #eviron: wsgi environ path
    #start_response:Function creates the response


    def __call__(self, environ, start_respone):

        def done(status, headers, output):
            #usefull for debugging
            #returns the output(actual static file)
            #also it produces the response using the start_response()
            start_respone(status, headers.items())
            return output

        #get the path_info see PEP 333
        path_info = environ['PATH_INFO']

        #remove leading '/' from path (URI)
        if path_info[0]=='/':
            path_info = path_info[1:]

        #actual file path in filesystem
        file_path = os.path.normpath((os.path.join(self.static_file_root, path_info)))

        #prevent escaping out of paths bellow media root (e.g via '..')
        if not file_path.startswith(self.static_file_root):
            status = '401 UNAUTHORIZED'
            headers = {'Content_type':'text/plain'}
            output = ['Permission denied. Illegal  Path']
            return done(status, headers, output)

        #Only allow GET and HEAD requests not PUT, POST, DELETE
        if not (environ['REQUEST_METHOD'] == 'GET' or environ['REQUEST_METHOD'] == 'HEAD'):
            status = '405 METHOD NOT ALLOWED'
            headers = {'Content_type':'text/plain'}
            output = SimpleResponse(['405:Method not allowed'])
            output.status_code = 405
            return done(status, headers, output)

        if not (os.path.exists(file_path)):
            status = "404 NOT FOUND"
            headers = {'Content_type':'text\plain'}
            output = SimpleResponse(['Page not found %s' %file_path])
            output.status_code = 404
            return done(status, headers, output)

        try:
            fp = open(file_path, 'rb')
        except IOError:
            status = '401 UNAUTHORIZED'
            headers = {'Content_type':'text/plain'}
            output = SimpleResponse(['Permission denied %s' %file_path])
            output.status_code = 401
            return done(status, headers, output)

        #This is a very simple implementation of conditional GET with
        #the Last-Modified header. It makes media files a bit speedier
        #because the files are only read off disk for the first request
        #(assuming the browser/client supports conditional GET).

        #mimetype needs to be ascii not uinicode, as django is all unicode, need to do conversion

        mtime = http_date(os.stat(file_path)[stat.ST_MTIME]).encode('ascii','ignore')
        if environ.get('HTTP_IF_MODIFIED_SINCE', None) == mtime:
            headers = {'Last-Modified':mtime}
            status = '304 NOT MODIFIED'
            output = SimpleResponse()
            output.status_code = 304
        else:
            status = '200 OK'
            mime_type = mimetypes.guess_type(file_path)[0]
           if mime_type:
                headers = {'Content_type':mime_type}
           output = BlockIteratorResponse(fp)

       return done(status, headers,output)

我在调用中收到有关在使用之前未初始化标头的错误...可能是因为所有标头都在内部。错误是

UnboundLocalError:Local variable "headers" referenced before assignment

有趣的是,我只在Mozilla上收到此错误,但网络正常,一切都正常,并且在我登录我的网页后,它不再显示错误。

我应该在调用开始时初始化标头变量,如

headers = {}

为什么它只发生在firefox中?

1 个答案:

答案 0 :(得分:0)

如果您想使用CherryPy提供静态内容,则应使用内置工具 - 请参阅Serving Static Content。我想你需要创建一个仅提供静态内容的CherryPy应用程序,然后将其与WSGIPathInfoDispatcher(...)的Django应用程序结合使用。

但你应该考虑的是使用nginx + uWSGI - 请参阅Setting up Django and your web server with uWSGI and nginx