欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

关于wsgi的理解(web服务器网关接口)2

shiping1 的头像

google  "make_server yield"
Python WSGI标准PEP-0333中说到一个WSGI是一个可调用callable的对象,这包含了一个函数,一个方法,一个类,或者拥有call方法的实例。下面我就对这句话做一个总结,举几个例子。这里的WSGI应用的功能都是返回请求的环境信息environ。

1 服务端

采用简单的WSGI服务器参考实现,如下:

if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    server = make_server('192.168.1.11', 7070, wsgi_application)
    server.serve_forever()

2 函数方法

这是最简单的方法,先调用start_response()处理返回头信息,函数再返回可迭代对象,比如列表或者字符串。

def app1(environ,start_response):
    start_response("200 OK",[("Content-type","text/plain")])
    content = []
    for k,v in environ.iteritems():
        content.append('%s:%s \n' % (k,v))
    return content#返回的列表或者字符串

相应的服务端:

server = make_server('192.168.1.11', 7070, app1)

3 带有call方法的实例

类定义中实现call方法,WSGI应用是这个类的一个实例。

class app2(object):
    def __init__(self):
       pass
    def __call__(self,environ,start_response):
       start_response("200 OK",[("Content-type","text/plain")])
       content = []
       for k,v in environ.iteritems():
           content.append('%s:%s \n' % (k,v))
       return content#返回的列表或者字符串

application = app2()

服务端:

server = make_server('192.168.1.11', 7070, application)

4 类class

用类作为WSGI应用不太一样,调用这个类时会产生一个类的实例,这个实例随后会需要iter迭代返回值。

class app3(object):
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        content = ''
        for k,v in self.environ.iteritems():
            content += '%s:%s \n' % (k,v)
        yield content#返回的是字符串

服务端:

server = make_server('192.168.1.11', 7070, app3)

这里注意,和上面的比较可以看出,如果需要把类的实例作为WSGI应用,则类中需要实现call方法,并且作为WSGI应用的应该是这个类的实例。

5 方法method

用一个方法来作为WSGI应用,那么这个方法不可能是实例方法(上面已经讲过),一种方式肯定就是类中的静态方法了,类中的静态方法,就当做一个全局函数一样理解吧。

class app4(object):
    def __init__(self):
        pass
    @staticmethod
    def wsgi(environ,start_response):
        start_response("200 OK",[("Content-type","text/plain")])
        content = []
        for k,v in environ.iteritems():
            content.append('%s:%s \n' % (k,v))
        return content#返回的是列表或者字符串

服务端:

server = make_server('192.168.1.11', 7070, app4.wsgi)

那么,类方法,可以用么,当然可以,classmethodstaticmethod在使用上可以看做只是参数有个区别而已,如下:

class app5(object):
    def __init__(self):
        print 'This is app5'
        pass
    @classmethod
    def wsgi(cls,environ,start_response):
        start_response("200 OK",[("Content-type","text/plain")])
        content = []
        for k,v in environ.iteritems():
            content.append('%s:%s \n' % (k,v))
        return content #返回列表或者字符串

服务端:

server = make_server('192.168.1.11', 7070, app5.wsgi)


来自  https://github.com/wangchang/site5-octopress/blob/master/source/_posts/2012-12-25-wsgi-application-style-base.markdown


Python WSGI标准 PEP-0333 中说到一个WSGI是一个可调用callable的对象,这包含了一个函数,一个方法,一个类,或者拥有call方法的实例。下面我就对这句话做一个总结,举几个例子。这里的WSGI应用的功能都是返回请求的环境信息environ。 

1 服务端


采用简单的WSGI服务器参考实现,如下:
if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    server = make_server('192.168.1.11', 7070, wsgi_application)
    server.serve_forever()

2 函数方法


这是最简单的方法,先调用 start_response() 处理返回头信息,函数再返回可迭代对象,比如列表或者字符串。
def app1(environ,start_response):
    start_response("200 OK",[("Content-type","text/plain")])
    content = []
    for k,v in environ.iteritems():
        content.append('%s:%s \n' % (k,v))
    return content#返回的列表或者字符串

相应的服务端:
server = make_server('192.168.1.11', 7070, app1)

3 带有call方法的实例


类定义中实现call方法,WSGI应用是这个类的一个实例。
class app2(object):
    def __init__(self):
       pass
    def __call__(self,environ,start_response):
       start_response("200 OK",[("Content-type","text/plain")])
       content = []
       for k,v in environ.iteritems():
           content.append('%s:%s \n' % (k,v))
       return content#返回的列表或者字符串

application = app2()

服务端:
server = make_server('192.168.1.11', 7070, application)

4 类class


用类作为WSGI应用不太一样,调用这个类时会产生一个类的实例,这个实例随后会需要 iter 迭代返回值。
class app3(object):
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        content = ''
        for k,v in self.environ.iteritems():
            content += '%s:%s \n' % (k,v)
        yield content#返回的是字符串

服务端:
server = make_server('192.168.1.11', 7070, app3)

这里注意,和上面的比较可以看出,如果需要把类的实例作为WSGI应用,则类中需要实现call方法,并且作为WSGI应用的应该是这个类的实例。

5 方法method


用一个方法来作为WSGI应用,那么这个方法不可能是实例方法(上面已经讲过),一种方式肯定就是类中的静态方法了,类中的静态方法,就当做一个全局函数一样理解吧。
class app4(object):
    def __init__(self):
        pass
    @staticmethod
    def wsgi(environ,start_response):
        start_response("200 OK",[("Content-type","text/plain")])
        content = []
        for k,v in environ.iteritems():
            content.append('%s:%s \n' % (k,v))
        return content#返回的是列表或者字符串

服务端:
server = make_server('192.168.1.11', 7070, app4.wsgi)

那么,类方法,可以用么,当然可以, classmethod 和 staticmethod 在使用上可以看做只是参数有个区别而已,如下:
class app5(object):
    def __init__(self):
        print 'This is app5'
        pass
    @classmethod
    def wsgi(cls,environ,start_response):
        start_response("200 OK",[("Content-type","text/plain")])
        content = []
        for k,v in environ.iteritems():
            content.append('%s:%s \n' % (k,v))
        return content #返回列表或者字符串

服务端:
server = make_server('192.168.1.11', 7070, app5.wsgi)


上面中说到了WSGI应用的几种基本形式,这一节就来说一些高级的用法,所谓高级,我理解的也就是使用装饰器 @ ,WebOb,以及中间件的形式,当然,还有一些更有意思的用法,比如Paste.Deploy这种载入WSGI应用的形式,我以后会做总结。还是和前篇 WSGI应用常见的几种写法-基本形式 一样,本文实现的WSGI应用都是一个回显请求环境信息的程序。 

1 WebOb


WebOb就是将请求和相应封装成Request和Response类,就可以使用一个类方法简化真个操作,如下,直接将一个字符串作为resp_body传给给Response对象,而不用考虑WSGI中的可迭代对象,这里要注意,Response对象 是一个WSGI应用 ,所以在最后的时候我们使用 resp(environ,start_response) 就返回了,我们不关心返回的细节问题了,而在标准WSGI中,这一步才只是WSGI应用的入口函数。
def app6(environ, start_response):
    req = Request(environ)
    resp_body = ''
    for k,v in req.environ.iteritems():
        resp_body += '%s:%s\n' % (k,v)
    resp = Response(body=resp_body)
    return resp(environ, start_response)

服务端:
server = make_server('192.168.1.11', 7070, app6)

2 用装饰器@,Controller


用装饰器@以后,重要的思想就是把WSGI应用关于返回流程的处理(包括header,状态等)和返回Body的处理分开,这样的话实际上一个应用只关注于产生返回的Body就可,而其他的处理流程则交给装饰器controller来完成,这个controller,不要理解成控制神马的,只是一个名字,其原意是作为WSGI中 一个资源的控制 ,不用太操心就当做一个名字就好。
def controller1(func):
    def application(environ,start_response):
        #do something else
        resp_body = func(environ)
        start_response("200 OK",[("Content-type","text/plain")])
        return resp_body
    return application

@controller1
def app7(environ):
    content = []
    for k,v in environ.iteritems():
        content.append('%s:%s \n' % (k,v))
    return content

服务端:
server = make_server('192.168.1.11', 7070, app7)

3 结合WebOb和装饰器


上面两种方式可能看起来没多大用,但是二者结合到一起,那就不一般了,这样子的话我们用装饰器controller来处理environ,并封装Request和Response,最后让应用函数来处理返回信息,只给出一个字符串Body就可以了。这会大大简化WSGI应用的开发流程。
def controller2(func):
    def replacement(environ, start_response):
        req = Request(environ)
        try:
            resp_body = func(req)
        except exc.HTTPException, e:
            resp_body = e
        resp = Response(body=resp_body)#body must be a string
        resp.status = '200 very OK'
        return resp(environ, start_response)
    return replacement

@controller2
def app8(req):
    ret = ''
    for k,v in req.environ.iteritems():
        ret = ret + '%s:%s \n' % (k,v)
    return ret

服务端:
    server = make_server('192.168.1.11', 7070, app8)

以上是用装饰器来装饰一个函数,还有一种用法,用装饰器来装饰一个类。
def controller3(cls):
    def replacement(environ, start_response):
        req = Request(environ)
        instance = cls(req, **req.urlvars)
        method = req.method
        if method == 'GET':
            func = getattr(instance, method.lower())
            resp_body = func()
            if isinstance(resp_body, basestring):
                resp = Response(body=resp_body)
        return resp(environ,start_response)
    return replacement

class App9(object):
    def __init__(self,req,**args):
        self.req = req
    def get(self):
        body = ''
        for k,v in self.req.environ.iteritems():
            body += '%s"%s \n' % (k,v)
        return body

app9 = controller3(App9)

上面关于类的装饰器可以仔细琢磨一下哈,相应的服务端:
server = make_server('192.168.1.11', 7070, app9)

4 总结


两篇文章我一共说明了9种WSGI应用的写法,当然WSGI只是一个协议,相应的实现还是很灵活的,以后再实践中再分享一些新的用法。整个代码我使用Gist存放,连接在此: https://gist.github.com/4378216 
原创文章,转载请注明:  转载自 Wang Chang's Blog 
本文链接地址:   http://blog.wachang.net/2013/03/wsgi-application-style-adv/ 


来自  http://www.boyunjian.com/do/article/snapshot.do?uid=8719811118731500360




wsgi规则

194 views, python, by 魏 哲.
Web服务器网关接口Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器Web应用程序框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。
def app(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    yield "Hello world!\n"
    time.sleep(5)
    yield "END\n"

入口处提供一个start_response,用于回流(回调,callback),入口会连接到出口的一个函数,并传递environ字典和start_response作为参数;

而出口处的函数先是调用start_response并传递status和header,然后return返回完整content。或者使用yiled分部分返回content,实现长链接。

from wsgiref.simple_server import make_server

def hello_world_app(environ, start_response):
    status = '200 OK' # HTTP Status
    headers = [('Content-type', 'text/plain')] # HTTP Headers
    start_response(status, headers)
    # The returned object is going to be printed
    return ["Hello World"]

httpd = make_server('', 8000, hello_world_app)
print "Serving on port 8000..."
# Serve until process is killed
httpd.serve_forever()

来自  https://blog.weizhe.net/?p=46



ubuntu下用uwsgi+nginx布署python WEB项目


标签: linux uwsgi nginx
浏览:246   分享人:wei   创建时间:2013-05-09 17:58:14   修改时间:2013-05-09 17:58:14

1.安装nginx,uwsgi以及uwsgi-plugin-python

比如:apt-get install nginx,uwsgi,uwsgi-plugin-python

2.写一个测试文件叫wsgi_httpsvr.py,保存到/home/test_wsgi目录下,内容如下:

 

from wsgiref.simple_server import make_server

def application(environ, start_response):
    status = '200 OK' # HTTP Status
    headers = [('Content-type', 'text/plain')] # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    yield "Hello World"

if __name__=='__main__':
    httpd = make_server('', 8000, application)
    print "Serving on port 8000..."
    # Serve until process is killed
    httpd.serve_forever()

3.在/etc/uwsgi/apps-available下创建一个名叫test_wsgi.xml的配置文件(名称随便),内容如下:

<uwsgi>
    <socket>127.0.0.1:9006</socket>
    <plugins>python</plugins>
    <chdir>/home/test_wsgi</chdir>
    <module>wsgi_httpsvr</module>
</uwsgi>

然后在/etc/uwsgi/apps-enabled下创建一下这个配置文件的link,比如:

ln -s /etc/uwsgi/apps-available/test_wsgi.xml /etc/uwsgi/apps-enabled/test_wsgi.xml

 

 

4.在/etc/nginx/sites-available下创建nginx配置文件(名称随便,这里叫test_wsgi),内容如下:

 

    server {
        listen   80; ## listen for ipv4
        server_name wzw.th360.cn;
        #charset koi8-r;
        access_log  /var/log/nginx/test-wsgi.access.log access;
        # root   html

        location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to index.html
            #try_files      $uri =404;
            #try_files $uri $uri/ /index.html;
            include        uwsgi_params;
            uwsgi_pass     127.0.0.1:9006;
            #uwsgi_pass     unix:///tmp/test_wsgi.socket;
        }
    }
5.执行如下指令:

 

service uwsgi restart

service nginx reload

======================================================

很奇怪,配置uwsgi的socket为/tmp/test_wsgi.socket方式时,死活不成功,虽然tmp目录下也生成socket文件了,而且服务也正常启动,但是访问nginx时报502 back gateway错误,暂不知道什么原因

 

=======================================================

以下是两个真实布署django的uwsgi配置文件和nginx的配置文件例子:

 

<uwsgi>
    <socket>127.0.0.1:9009</socket>
    <master/>
    <uid>www-data</uid>
    <gid>www-data</gid>
    <plugins>python</plugins>
    <chdir>/mnt/data/home/websearch/wwwroot/new_cntsyy/th_payment/payment</chdir>
    <pythonpath>..</pythonpath>
    <module>wsgi</module>
</uwsgi>
server {
        listen       80;
        server_name  test.th010.com test.th360.cn;
        root /mnt/data/home/websearch/wwwroot/new_cntsyy/th_payment;

        access_log  /var/log/nginx/test.th360.cn.access.log access;
        #error_log  /var/log/nginx/test.th360.cn.error.log access;

        #配置django admin需要的文件
        location ~* ^/media/(css|img|js)/.*$ {
                root /usr/local/lib/python2.7/dist-packages/django/contrib/admin;
                expires 30d;
                break;
        }

        location ^~ /static  {
            autoindex on;
            alias   /home/websearch/wwwroot/new_cntsyy/th_payment/payment/static;
        }
        location / {
                ###uwsgi config###
                include        uwsgi_params;
                uwsgi_pass     127.0.0.1:9009;
                uwsgi_param    UWSGI_SCHEME $scheme;
                uwsgi_param    SERVER_SOFTWARE    nginx/$nginx_version;

        }
}

 

 

uwsgi官方文档:

http://uwsgi-docs.readthedocs.org/en/latest/WSGIquickstart.html#installing-uwsgi-with-python-support



来自  http://mysrc.sinaapp.com/view_note/?id=142

 

Wsgiref Error: AttributeError: 'NoneType' object has no attribute 'split'

wsgiref错误:意思:“nonetype的对象没有属性“分裂”

Tags: python wsgi source
标签: python wsgi source
 

问题 (Question)

I am trying to implement my own version of wsgiref for learning purpose and i ended up here.

from wsgiref.simple_server import make_server

class DemoApp():
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self, status):
        self.status = '200 OK'
        response_headers = [('Content-type','text/plain')]
        self.start(status, response_headers)
        return ["Hello World"]


if __name__ == '__main__':
    httpd = make_server('', 1000, DemoApp)
    print("Serving on port 1000")
    httpd.serve_forever()

When i go to port 1000, i am getting the attribute error.

AttributeError: 'NoneType' object has no attribute 'split'

Where i am leaving mistakes ?

Stacktrace

Serving on port 1000
Traceback (most recent call last):
  File "C:\Python27\lib\wsgiref\handlers.py", line 86, in run
    self.finish_response()
  File "C:\Python27\lib\wsgiref\handlers.py", line 131, in finish_response
    self.close()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 33, in close
    self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
127.0.0.1 - - [11/Jan/2014 12:40:09] "GET / HTTP/1.1" 500 59
Traceback (most recent call last):
  File "C:\Python27\lib\SocketServer.py", line 295, in _handle_request_noblock
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 54469)
    self.process_request(request, client_address)
  File "C:\Python27\lib\SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "C:\Python27\lib\SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Python27\lib\SocketServer.py", line 649, in __init__
    self.handle()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 124, in handle
    handler.run(self.server.get_app())
  File "C:\Python27\lib\wsgiref\handlers.py", line 92, in run
    self.close()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 33, in close
    self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'

我想学习的目的,我自己版本的wsgiref实施和我结束这里。

from wsgiref.simple_server import make_server

class DemoApp():
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self, status):
        self.status = '200 OK'
        response_headers = [('Content-type','text/plain')]
        self.start(status, response_headers)
        return ["Hello World"]


if __name__ == '__main__':
    httpd = make_server('', 1000, DemoApp)
    print("Serving on port 1000")
    httpd.serve_forever()

当我去到端口1000,我得到的属性错误。

AttributeError: 'NoneType' object has no attribute 'split'

在我离开的错误?

堆栈跟踪

Serving on port 1000
Traceback (most recent call last):
  File "C:\Python27\lib\wsgiref\handlers.py", line 86, in run
    self.finish_response()
  File "C:\Python27\lib\wsgiref\handlers.py", line 131, in finish_response
    self.close()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 33, in close
    self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
127.0.0.1 - - [11/Jan/2014 12:40:09] "GET / HTTP/1.1" 500 59
Traceback (most recent call last):
  File "C:\Python27\lib\SocketServer.py", line 295, in _handle_request_noblock
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 54469)
    self.process_request(request, client_address)
  File "C:\Python27\lib\SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "C:\Python27\lib\SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Python27\lib\SocketServer.py", line 649, in __init__
    self.handle()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 124, in handle
    handler.run(self.server.get_app())
  File "C:\Python27\lib\wsgiref\handlers.py", line 92, in run
    self.close()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 33, in close
    self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
 

最佳答案 (Best Answer)

How about this, you need to yield the output than returning it.

from wsgiref.simple_server import make_server

class DemoApp:

    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        yield 'Hello world!'


if __name__ == '__main__':
    httpd = make_server('', 1000, DemoApp)
    print("Serving HTTP on port 1000...")
    httpd.serve_forever()

这个怎么样,你需要yield产量比返回。

from wsgiref.simple_server import make_server

class DemoApp:

    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        yield 'Hello world!'


if __name__ == '__main__':
    httpd = make_server('', 1000, DemoApp)
    print("Serving HTTP on port 1000...")
    httpd.serve_forever()

答案 (Answer) 2

DemoApp is called; The return value of DemoApp.__init__ is used.

DemoApp.__init__ returns nothing (You can't return anything in constructor).

Try following instead of DemoApp class:

def DemoApp(environ, start_response):
    response_headers = [('Content-type','text/plain')]
    start_response('200 OK', response_headers)
    return ["Hello World"]

Using class (Use __call__ instead of __iter__):

from wsgiref.simple_server import make_server

class DemoApp:
    def __call__(self, environ, start_response):
        response_headers = [('Content-type','text/plain')]
        start_response('200 OK', response_headers)
        return ["Hello World"]


if __name__ == '__main__':
    httpd = make_server('', 1000, DemoApp()) # Don't forget instantiate a class.
    #                                    ^^
    print("Serving on port 1000")
    httpd.serve_forever()

DemoApp调用的返回值;DemoApp.__init__使用。

DemoApp.__init__(你不能返回不返回任何构造函数)。

尝试下面而不是DemoApp

def DemoApp(environ, start_response):
    response_headers = [('Content-type','text/plain')]
    start_response('200 OK', response_headers)
    return ["Hello World"]

使用类(使用__call__而不是__iter__):

from wsgiref.simple_server import make_server

class DemoApp:
    def __call__(self, environ, start_response):
        response_headers = [('Content-type','text/plain')]
        start_response('200 OK', response_headers)
        return ["Hello World"]


if __name__ == '__main__':
    httpd = make_server('', 1000, DemoApp()) # Don't forget instantiate a class.
    #                                    ^^
    print("Serving on port 1000")
    httpd.serve_forever()

 







普通分类: